inttypes.h and Extended Integer Types
This chapter covers <inttypes.h>: the format macros for printing and scanning fixed-width integer types portably, plus the related intmax_t/uintmax_t.
Why This Matters
Fixed-width types (int32_t, uint64_t, etc.) have implementation-defined underlying types, so %d or %lld is not portable. <inttypes.h> provides the correct format specifiers, eliminating a whole class of portability bugs.
Prerequisites
c.core.14— integer types and conversions.
Core Concept
<inttypes.h> includes <stdint.h> and defines macros that expand to the correct format specifier for each fixed-width type.
Printing
#include <inttypes.h>
#include <stdio.h>
int32_t a = -5;
uint64_t b = 10000000000ULL;
printf("%" PRId32 "\n", a); /* PRId32 expands to the right %...d */
printf("%" PRIu64 "\n", b);
printf("%" PRIx64 "\n", b); /* hex */
The macros are string literals, so they must be concatenated with the format string using adjacent string literal concatenation ("%" PRId32).
Scanning
int32_t x;
scanf("%" SCNd32, &x);
SCNd32 is the scan counterpart.
Key Macros
| Format | Signed | Unsigned |
|---|---|---|
| decimal | PRIdN | PRIuN |
| octal | PRIoN | PRIoN |
| hex | PRIxN/PRIXN | PRIxN/PRIXN |
| scan | SCNdN/SCNuN/SCNxN | same |
Where N is 8, 16, 32, 64, LEASTN, FASTN, MAX, or PTR.
Examples
Portable printing of all widths
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
int8_t a = -1;
uint8_t b = 255;
int64_t c = -9000000000000000000LL;
uintmax_t d = UINTMAX_MAX;
printf("%" PRId8 " %" PRIu8 "\n", a, b);
printf("%" PRId64 "\n", c);
printf("%" PRIuMAX "\n", d);
return 0;
}
How It Works
The implementation defines each macro as the correct string for its platform's underlying types. For example, on LP64, PRId64 expands to "ld", while on LLP64 it expands to "lld". The macro hides this difference.
Variations
intmax_t/uintmax_t
intmax_t/uintmax_t are the largest supported integer types. Use them when you need "the widest available integer" and format with PRIdMAX/PRIuMAX.
intptr_t/uintptr_t
For storing pointers in integers, format with PRIdPTR/PRIuPTR.
Common Mistakes
- Hard-coding
%d/%lldfor fixed-width types. - Forgetting string concatenation (writing
"%PRId32"instead of"%" PRId32). - Using the wrong macro for the signedness/width.
Undefined Behavior
- Mismatched format specifier and argument type (using
%dforint64_twhen
the underlying type is long long) is UB. <inttypes.h> macros prevent this.
Portability
- The whole purpose of
<inttypes.h>is portability; use it consistently with
fixed-width types.
Under the Hood
The macros are preprocessor string constants. They are resolved at compile time; there is no run-time cost.
Practical Usage
- Always use
<inttypes.h>macros when printing/scanning fixed-width types. - Use
intmax_t/uintmax_tfor "widest integer" needs. - Use
PRIdPTR/PRIuPTRfor pointer-sized integers.
Exercises
1. Write a program that prints int8_t, uint64_t, and intptr_t values portably using the macros. 2. Demonstrate what happens (or what warning you get) if you use %d for a int64_t. 3. Use SCNd32 to read an int32_t.
Deep Challenge
Write a portable logging function that prints a uint64_t in hex with a fixed width and zero padding, using <inttypes.h> macros only. Explain why you cannot hard-code the width.
Related Concepts
c.core.3— fixed-width integer types.c.core.14— conversions.
References
- ISO/IEC 9899:2018 §7.8 (inttypes.h).
Verification
<inttypes.h>macros expand to correct specifiers.VERIFIED- String-literal concatenation is required.
VERIFIED - No example was executed during generation unless noted. `Execution not
verified.`
Progress
- [ ] Read
- [ ] Understand
- [ ] Complete examples
- [ ] Complete exercises
- [ ] Complete deep challenge
Concept checkboxes
- [ ] PRIdN/PRIuN/PRIxN macros
- [ ] SCNdN/SCNuN/SCNxN macros
- [ ] intmax_t/uintmax_t
- [ ] intptr_t/uintptr_t formatting
Mastery levels
| Concept | Current level (0–8) | Target level |
|---|---|---|
| c.lib.inttypes | 0 | 5 |