C/C++ printf Format Specifiers

All printf/scanf format specifiers with type, width, precision and length modifiers.

Reference for C and C++ printf and scanf format specifiers — %d, %u, %x, %f, %e, %g, %s, %c, %p, %%, plus length modifiers (l, ll, h, z, j) and width/precision flags — with the exact argument type each expects.

Why must I use %zu for size_t?

size_t is an unsigned type whose width varies by platform, so printing it with %u or %lu is undefined behaviour on systems where the sizes differ. The z length modifier with u, as in %zu, tells printf the argument is exactly a size_t.

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%lld with 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 modifiershh (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

Notes

  • %i and %d are identical in printf but differ in scanf, where %i auto-detects the base from a 0x/0 prefix and %d is decimal only.
  • For scanf, every non-%c/%s argument must be a pointer: scanf("%d", &n). Forgetting the & is a frequent crash.
  • %n writes 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 an int argument: printf("%*.*f", 8, 3, d).