C/C++ Arena

Step 3 of 8

Signed overflow is undefined

For signed integers, going past INT_MAX (or below INT_MIN) is undefined behavior (UB). "Undefined" doesn't mean "wraps around like unsigned". It means the C standard places no requirements at all on what happens, and the compiler is allowed to assume it never occurs.

That assumption is used by optimizers. For example, a compiler may delete a check like if (x + 1 < x) entirely, reasoning that in a correct program x + 1 can never be less than x. So "detect overflow after it happened" doesn't work: the detection code itself can vanish.

Check before, with operations that can't overflow

To know whether a + b would overflow, rearrange the question so no step can overflow:

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

int checked_mul(int a, int b, int *out) {
    long long wide = (long long)a * b;
    if (wide > INT_MAX || wide < INT_MIN) {
        return 0;
    }
    *out = (int)wide;
    return 1;
}

int main(void) {
    int r = 0;
    int ok = checked_mul(50000, 50000, &r);
    printf("%d %d\n", ok, r);
    ok = checked_mul(-300, 7, &r);
    printf("%d %d\n", ok, r);
    return 0;
}
0 0
1 -2100

This example checks multiplication a different way: doing the math in a wider type (long long holds any product of two ints) and then checking the range. That works when a wider type exists; the rearranged comparisons work even for the widest type.

Leaving *out untouched on failure lets the caller rely on its previous value. (GCC and Clang also offer __builtin_add_overflow, and C23 standardizes ckd_add in <stdckdint.h>.)

Your turn: write int checked_add(int a, int b, int *out). If the sum fits, store it in *out and return 1. Otherwise return 0 and leave *out untouched.

Previous: Unsigned wraparound Next: Fixed-width types