Skip to Content
Course content

114: Integer Limits with limits.h

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this happen countless times in code reviews: a developer writes a loop or a calculation assuming that a standard int will always be 32 bits, meaning it can hold up to about 2.1 billion. It seems like a safe bet because, on your modern laptop or desktop, it probably is. But the moment that code gets ported to a smaller embedded system or a legacy architecture, it crashes or behaves erratically because on that system, an int might only be 16 bits.

The Myth of the "Universal" Integer Size

You might think that int is a fixed size across all C compilers. It isn't. The C standard only guarantees a minimum size. If you write code that assumes a specific limit, you're building a time bomb. Look at this snippet:

// Dangerous assumption: thinking int is always 32-bit
int population = 100000; 
int multiplier = 30000;
int total = population * multiplier; 
// total is now 3,000,000,000. 
// On a 32-bit signed int, this overflows into a negative number.

If you run this on a machine where INT_MAX is 2,147,483,647, your total variable will wrap around and give you a nonsensical negative value. You didn't get a compiler error; you got a logic error that could haunt your production environment for months.

Letting limits.h Define the Boundaries

Instead of guessing or relying on the documentation of one specific compiler, we use <limits.h>. This header file provides a set of macros that tell you exactly what the limits are for the specific environment you are currently compiling for. It's the only way to write truly portable C code.

The most common constants you'll use are:

  • INT_MAX and INT_MIN: The maximum and minimum values for a signed int.
  • UINT_MAX: The maximum value for an unsigned int.
  • LONG_MAX and LONG_MIN: The limits for the long type.
  • CHAR_BIT: The number of bits in a byte (usually 8, but not guaranteed by the standard).

I always recommend using these constants when you're performing input validation or checking for potential overflows before they happen. For example, if you're writing a function that adds two integers, you shouldn't just add them and hope for the best. You should check if the operation is safe first:

#include <stdio.h>
#include <limits.h>

int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        printf("Overflow detected!\n");
        return INT_MAX; // Or handle the error appropriately
    }
    return a + b;
}

By subtracting a from INT_MAX, we can see if there is enough "room" left for b without actually triggering the overflow. It's a simple trick, but it's the difference between professional software and a lucky guess.




📋 Practical Task

Building an Integer Overflow Guard

Your task is to create a program that acts as a safety validator for user-provided integers. The program should prompt the user to enter two signed integers. Before performing any addition, the program must check if the sum would exceed the limits defined in <limits.h>.

Requirements:

  • Include <limits.h> to access INT_MAX and INT_MIN.
  • Implement a check for positive overflow (where the sum would exceed INT_MAX).
  • Implement a check for negative overflow (where the sum would be less than INT_MIN).
  • If an overflow is detected, print a specific warning message and do not perform the addition.
  • If the operation is safe, print the resulting sum.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.