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.
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.
#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;}
sizeof(uint8_t) = 1 sizeof(int16_t) = 2 sizeof(uint32_t) = 4 a + b as int: 300 a + b as uint8_t: 44