The C standard specifies only minimum sizes for its built-in integer types — char is at least 8 bits, short and int at least 16 bits, long at least 32 bits, long long at least 64 bits — with the exact size left to the compiler and platform. On virtually every modern desktop and server platform, int happens to be 32 bits, but this is convention, not a guarantee the language enforces; code that needs an exact width should use the fixed-width types (int32_t, uint64_t, etc.) from stdint.h instead of assuming int's size.
Basic types and sizeof
sizeof is a compile-time operator, not a function call in the usual sense — it returns the size in bytes of its operand's type, and is the correct way to check a type's actual size on the current platform rather than assuming one.
#include <stdio.h>
int main(void) {
printf("char: %zu bytes\n", sizeof(char)); // guaranteed exactly 1
printf("int: %zu bytes\n", sizeof(int)); // usually 4, but NOT guaranteed
printf("long: %zu bytes\n", sizeof(long)); // 4 or 8, depends on platform
printf("double: %zu bytes\n", sizeof(double)); // usually 8
return 0;
}Fixed-width types: when the exact size matters
stdint.h (part of the standard since C99) defines types with guaranteed exact widths — the right choice whenever code genuinely depends on a specific bit width, such as reading a binary file format or a network protocol.
#include <stdint.h>
int32_t exactlyFourBytes = 100000; // guaranteed exactly 32 bits, everywhere
uint64_t exactlyEightBytes = 1; // guaranteed exactly 64 bits, unsignedSigned vs unsigned, and a real overflow gotcha
Unsigned integer underflow wraps around silently rather than going negative — a genuinely common source of real bugs, especially in a loop condition that assumes an unsigned counter can safely go below zero.
unsigned int count = 0;
count = count - 1;
// count is now a very large positive number (UINT_MAX), NOT -1 —
// unsigned arithmetic wraps around silently, it never goes negative