Start with a stream argument, then read the format string and its matching value: `#include <stdio.h>\nint main(void) {\n int count = 3;\n fprintf(stderr, "count=%d\\n", count);\n return 0;\n}`. `fprintf` writes formatted output to `stderr`; unlike `printf`, it lets the call select the destination stream. section 8.3.4 section 16.2
Read the call from its visible format string to the rules governing its variadic arguments:
- Supply a format string followed by an arbitrary number of values, but make the values correspond exactly to the `%` conversion specifiers; otherwise behavior is undefined. section 8.3.4
- Compose conversions from flags, width, precision, modifiers, and a required specifier; the specifier selects the output conversion. section 8.3.4
- Choose `%d` or `%u` for integer values, `%x` for unsigned bit patterns, and `%g` for ordinary decimal floating-point output. section 8.3.4
- Use a modifier when the argument's exact type requires it; interpreting a value with the wrong modifier can cause a mismatch. section 8.3.4
int printf(char const format[static 1], ...);
int fprintf(FILE* stream, char const format[static 1], ...);
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":3}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":3}],[{\"line\":0,\"ch\":4},{\"line\":0,\"ch\":10}],[{\"line\":1,\"ch\":5},{\"line\":1,\"ch\":11}],[{\"line\":0,\"ch\":11},{\"line\":0,\"ch\":21}],[{\"line\":1,\"ch\":26},{\"line\":1,\"ch\":36}],[{\"line\":0,\"ch\":29},{\"line\":0,\"ch\":35}],[{\"line\":1,\"ch\":44},{\"line\":1,\"ch\":50}],[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":3}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":3}],[{\"line\":1,\"ch\":4},{\"line\":1,\"ch\":11}],[{\"line\":1,\"ch\":12},{\"line\":1,\"ch\":16}],[{\"line\":0,\"ch\":11},{\"line\":0,\"ch\":21}],[{\"line\":1,\"ch\":26},{\"line\":1,\"ch\":36}],[{\"line\":0,\"ch\":29},{\"line\":0,\"ch\":35}],[{\"line\":1,\"ch\":44},{\"line\":1,\"ch\":50}]]"}
!@%STYLE%@!
Compare the declarations of `printf` and `fprintf`: both accept a format string and variadic arguments, while `fprintf` additionally accepts a `FILE*` stream. section 8.3.4
Format-safe tracing
A debugging macro can forward a literal format string and value to `fprintf`: `#define TRACE_PRINT2(F, X) do { if (TRACE_ON) fprintf(stderr, "" F "\\n", X); } while (false)`. Keeping `F` as a string literal allows modern compilers to check format specifiers against arguments, even when the call is optimized out of a non-debug build. Passing an arbitrary modifiable character pointer instead can allow an invalid or malicious format to crash the program or divulge secrets. section 16.2

