Fixed-Width Integers in C: The stdint.h Header
In C programming, traditional integer types such as int
or long can vary in size across different hardware
platforms and compilers, often leading to portability bugs. To solve
this problem, the C99 standard introduced fixed-width integer types like
int32_t and uint64_t, which guarantee exact
bit widths across all compliant platforms. This article covers the
specific header file that defines these types, explains the available
variations, and demonstrates how to implement them in your code.
The Standard Header:
<stdint.h>
The standard header that provides fixed-width integer types in the C
language is <stdint.h>. When programming in C++, the
equivalent header is <cstdint>, which places the same
types within the std namespace as well as the global
namespace.
Including this header allows developers to declare integer variables with explicit memory footprints, ensuring cross-platform predictability for binary data processing, memory-mapped I/O, network protocols, and cryptographic algorithms.
#include <stdint.h>Categories of Fixed-Width Integer Types
The <stdint.h> header categorizes integer
definitions into several distinct groups depending on performance and
architectural requirements:
1. Exact-Width Integer Types
These types guarantee exact sizes without any padding bits:
- Signed:
int8_t,int16_t,int32_t,int64_t - Unsigned:
uint8_t,uint16_t,uint32_t,uint64_t
If a specific architecture cannot natively support an exact width
(for example, a system with 32-bit minimum addressable units cannot
define int8_t), the corresponding type will not be provided
by that implementation.
2. Minimum-Width Integer Types
These guarantee at least the specified number of bits, but the implementation may choose a larger type if it is more suitable:
- Signed:
int_least8_t,int_least16_t,int_least32_t,int_least64_t - Unsigned:
uint_least8_t,uint_least16_t,uint_least32_t,uint_least64_t
3. Fastest Minimum-Width Integer Types
These represent the fastest integer types on the target hardware that have at least the designated width:
- Signed:
int_fast8_t,int_fast16_t,int_fast32_t,int_fast64_t - Unsigned:
uint_fast8_t,uint_fast16_t,uint_fast32_t,uint_fast64_t
4. Pointer-Holding Integers
These types are guaranteed to be wide enough to store a void pointer safely:
intptr_t(signed)uintptr_t(unsigned)
5. Maximum-Width Integers
These define the largest supported integer widths on the system:
intmax_t(signed)uintmax_t(unsigned)
Practical Implementation Example
#include <stdio.h>
#include <stdint.h>
int main(void) {
int32_t signed_integer = -2147483648;
uint64_t unsigned_large_integer = 18446744073709551615ULL;
printf("Size of int32_t: %zu bytes\n", sizeof(signed_integer));
printf("Size of uint64_t: %zu bytes\n", sizeof(unsigned_large_integer));
return 0;
}Formatted Printing with
<inttypes.h>
Because the underlying fundamental type for fixed-width integers
varies (e.g., int64_t might be defined as long
on 64-bit Linux, but long long on 64-bit Windows), standard
format specifiers like %d or %lld can trigger
compiler warnings.
To print these types portably, include
<inttypes.h>, which wraps
<stdint.h> and provides standard format macros:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
int32_t count = 42;
uint64_t big_number = 10000000000ULL;
printf("Count: %" PRId32 "\n", count);
printf("Big Number: %" PRIu64 "\n", big_number);
return 0;
}