Integer overflow

In computer programming, an integer overflow occurs when an arithmetic operation attempts to create a numeric value that is outside of the range that can be represented with a given number of digits.

For easy understanding, let’s take 8-bit integer.

type bit min max
int8_t 8 -(2^7) = -128 2^7 - 1
uint8_t 8 0 2^8 - 1 = 255

8-bit unsigned int overflow

uint8_t can represent 0 ~ 255. According to wraparound, 255 + 1 is zero not 256.
This is guaranteed by the C standard.

Wraparound: wrapping of numerical value in case of underflow or overflow

uint8_t ui = 255;
/// ++ui is 0 - overflow occured

8-bit signed int overflow

In case of int8_t, it can represent -128 ~ 127. According to wraparound, 127 + 1 is -128 not 128.

int8_t i = 127;
/// ++ui is -128 - overflow occured

But, The C Standard says that if a program has signed integer overflow its behavior is undefined. And the undefined behavior can even precede the overflow.


Why signed overflow is undefined behavior?

There are two ways to represent signed int. One is one’s complemnet, another is two’s complement.

type bit min max zero
one’s 8 -(2^7) + 1 = -127 2^7 - 1 = 127 -0, +0
two’s 8 -(2^7) = -128 2^7 - 1 = 127 0

Operations of signed-int depends on ALU(Arithmetic logic unit). So, compiler can not expect the value of overflow. (127 + 1 is -128? or -127?)

But since most of latest hardwares use two’s complemnt, we can exepect it. (Refer this.)

Anyway signed overflow is undefined behavior.


Simple detection of overflow, underflow

8-bit unsigned value

8-bit signed value


Compiler built-in functions with overflow checking

We can detect overflow with several ways. But compiler can remove our overflow checking statement for optimazation.
(In simple terms, a + b > b is always true.)

So, the best way for preventing overflow is using built-in functions. Below is gcc’s build-in functions.

bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
bool __builtin_sadd_overflow (int a, int b, int *res)
bool __builtin_saddl_overflow (long int a, long int b, long int *res)
bool __builtin_saddll_overflow (long long int a, long long int b, long long int *res)
bool __builtin_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
bool __builtin_uaddl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
bool __builtin_uaddll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)