Table of Contents

stdint.h

Write int assuming it is 32 bits, run the code on a 16-bit microcontroller, and things break silently. stdint.h (C99) solves this by providing integer types with guaranteed widths, so you can write code that means exactly what it says regardless of platform.

The main type families:

#include <stdint.h>
 
// exact width — guaranteed to be exactly N bits
int8_t    int16_t    int32_t    int64_t
uint8_t   uint16_t   uint32_t   uint64_t
 
// fast — at least N bits, chosen for speed on the platform
int_fast8_t   int_fast16_t   int_fast32_t   int_fast64_t
uint_fast8_t  uint_fast16_t  uint_fast32_t  uint_fast64_t
 
// least — smallest type with at least N bits
int_least8_t   int_least16_t   int_least32_t   int_least64_t
uint_least8_t  uint_least16_t  uint_least32_t  uint_least64_t
 
// widest available integer type
intmax_t    uintmax_t
 
// types wide enough to hold a pointer
intptr_t    uintptr_t

Corresponding limit macros: INT8_MIN, INT8_MAX, UINT8_MAX, INT64_MIN, INT64_MAX, UINT64_MAX, and so on.

Constant macros suffix the literal to the correct type:

uint32_t mask = UINT32_C(0xDEADBEEF);
int64_t  big  = INT64_C(-9000000000);

intptr_t and uintptr_t are wide enough to hold a pointer cast to an integer, which is useful for pointer tagging (storing flags in the low bits), hardware register addresses, and any place where you genuinely need to do arithmetic on a pointer value.

The exact-width types (int32_t, etc.) may not exist on platforms where no native type has exactly that width — they are optional. The least-width types are always present.

Practice

// compile: gcc -o inttest inttest.c
// run: ./inttest
// description: print sizes of standard integer types on this platform
 
#include <stdint.h>
#include <stdio.h>
 
int main(void) {
    printf("int8_t   = %zu bytes\n", sizeof(int8_t));
    printf("int16_t  = %zu bytes\n", sizeof(int16_t));
    printf("int32_t  = %zu bytes\n", sizeof(int32_t));
    printf("int64_t  = %zu bytes\n", sizeof(int64_t));
    printf("intptr_t = %zu bytes\n", sizeof(intptr_t));
    printf("INT32_MAX  = %d\n",  INT32_MAX);
    printf("UINT64_MAX = %llu\n", (unsigned long long)UINT64_MAX);
    return 0;
}

On a 64-bit Linux system you will see intptr_t as 8 bytes (matching the pointer width). On a 32-bit build (gcc -m32) it becomes 4. The exact-width types stay the same size on both, which is exactly the point.