C’s printf and scanf families are driven by format specifiers — a
percent sign, optional flags, width, precision, and a length modifier, ending in
a conversion letter. Because these functions are variadic, a mismatch between
the specifier and the argument type is undefined behaviour. This tool is a
searchable reference of every specifier and the exact type it expects.
How it works
A full specifier has the shape %[flags][width][.precision][length]conversion.
The conversion letter picks the base behaviour; the rest refine it:
- Integer conversions —
%d/%i(signed decimal),%u(unsigned),%o(octal),%x/%X(hex),%c(character),%hhd…%lldwith length modifiers. - Floating conversions —
%f/%F,%e/%E,%g/%G,%a/%A(hex float). - Other —
%s(string),%p(pointer),%%(literal percent),%n(store count — dangerous, often disabled). - Length modifiers —
hh(char),h(short),l(long),ll(long long),z(size_t),j(intmax_t),t(ptrdiff_t),L(long double).
Worked example
int n = 42; printf("%d\n", n); // 42
unsigned u = 42; printf("%#x\n", u); // 0x2a
double d = 3.14159; printf("%8.3f\n", d); // " 3.142"
size_t len = 7; printf("%zu\n", len); // 7
long long big = 9e9;printf("%lld\n", big); // 9000000000
char *s = "hello"; printf("%.3s\n", s); // hel
Flags in detail
Flags come immediately after the % and modify the output style:
| Flag | Effect |
|---|---|
- | Left-justify in the field width (default is right) |
+ | Always print a sign, even for positive numbers |
| space | Print a leading space for positive numbers |
# | Alternate form: 0x prefix for hex, 0 for octal, always decimal point for floats |
0 | Pad with zeros instead of spaces for numeric fields |
Combining flags: %-8d produces a left-aligned 8-character signed integer field; %+.2f forces a sign on a two-decimal float.
Common type mismatches that cause undefined behaviour
The most frequent type errors with printf:
- Passing a
longto%d(should be%ld) — undefined on 64-bit Windows wherelongis 32-bit but on 64-bit Linux wherelongis 64-bit can silently truncate. - Passing a
size_tto%uinstead of%zu— undefined on platforms wheresize_tis wider thanunsigned int. - Passing a
doublewhere%Lfexpects along double— different sizes, different calling conventions. - Passing
NULLto%s— many implementations print “(null)” but the C standard does not guarantee this; it is undefined behaviour.
Enable compiler warnings (-Wall -Wformat in GCC/Clang) to catch most format mismatches at compile time.
Notes
%iand%dare identical inprintfbut differ inscanf, where%iauto-detects the base from a0x/0prefix and%dis decimal only.- For
scanf, every non-%c/%sargument must be a pointer:scanf("%d", &n). Forgetting the&is a frequent crash. %nwrites the number of characters output so far through a pointer argument; it is a security risk and is disabled by hardened libc builds.- Width and precision can be passed dynamically with
*, consuming anintargument:printf("%*.*f", 8, 3, d). snprintfis always preferred oversprintf— it writes at mostnbytes including the null terminator, preventing buffer overflows.