C Programming 4 min read

Types and integer widths

C fixes only minimum sizes: int is 16 bits on an 8-bit AVR and 32 bits on a Cortex-M or a Linux MPU. <stdint.h> types such as uint8_t give exact widths. Small types are promoted to int before arithmetic, unsigned results wrap when stored, and signed overflow is undefined.

Two uint8_t variables, a = 200 and b = 100, each 8 bits wide. Before the addition both are promoted to int. The sum is computed in int and is 300. Storing that result back into a uint8_t keeps 300 mod 256, so the stored value is 44.
Two uint8_t values are widened to int, added, then cut back to 8 bits.

How wide is an int?

C does not fix the size of int. The standard only sets minimum ranges: an int must hold at least -32767 to 32767, so 16 bits are enough. With avr-gcc on an 8-bit AVR, int is 16 bits; on an Arm Cortex-M and on a Linux MPU it is 32 bits. sizeof counts bytes, and sizeof(char) is always 1.

For registers, protocol fields and anything stored in Flash or sent over a wire, include <stdint.h> and use exact-width types: uint8_t, int16_t, uint32_t. They are optional: a DSP whose smallest unit is 16 bits has no uint8_t, while uint_least8_t always exists. Plain int suits local maths and loop counters that stay below 32767. The C++ insight Types and operators uses the same types.

Signed, unsigned and overflow

Unsigned arithmetic wraps around modulo 2 to the power N: add 1 to a uint8_t holding 255, store the result, and you get 0. Signed overflow is undefined behaviour, so the compiler may assume it never happens. Converting an out-of-range value into a signed type, such as 300 into an int8_t, is implementation-defined instead. C23 requires two's complement, but signed overflow stays undefined.

Promotion: small types become int

Before arithmetic, types narrower than int, such as char, short and uint8_t, are promoted to int when int can hold all their values. So a + b with two uint8_t values of 200 and 100 is computed as the int 300. Storing it back into a uint8_t keeps 300 mod 256, which is 44.

promotion.cC
#include <stdint.h>#include <stdio.h>int main(void) {    printf("sizeof(uint8_t)  = %u\n", (unsigned)sizeof(uint8_t));    printf("sizeof(int16_t)  = %u\n", (unsigned)sizeof(int16_t));    printf("sizeof(uint32_t) = %u\n", (unsigned)sizeof(uint32_t));    uint8_t a = 200, b = 100;    int sum = a + b;                 /* promoted to int: 300 */    uint8_t sum8 = (uint8_t)(a + b); /* 300 mod 256 = 44 */    printf("a + b as int:     %d\n", sum);    printf("a + b as uint8_t: %u\n", (unsigned)sum8);    return 0;}
Output
sizeof(uint8_t)  = 1
sizeof(int16_t)  = 2
sizeof(uint32_t) = 4
a + b as int:     300
a + b as uint8_t: 44