Format Expects Argument of Type in C: Match printf Specifiers
A format warning means a conversion in printf's format string does not match the argument type supplied to it. Variadic arguments are not converted to fit the format string. A mismatch can produce undefined behavior even when the program appears to print the right value. Read both types in the diagnostic and correct the conversion, not just the warning.
Quick Fix Summary
Match int with %d, unsigned int with %u, long with %ld, size_t with %zu, and an object pointer converted to void * with %p. For fixed-width integers, use the PRI... macros from <inttypes.h>. Keep -Wformat=2 enabled.

Why This Error Happens
Why variadic calls need exact types
The compiler checks a known format string against the expressions after it. At runtime printf follows the format to retrieve arguments; the format does not communicate a conversion back to the caller. Calling conventions may pass integer and floating-point values differently. A mismatched conversion therefore is not merely a cosmetic formatting problem, and equal storage sizes are not a general justification for mixing types.
A portable specifier table
Use %d for int, %u for unsigned int, %ld for long, %lld for long long, %zu for size_t, and %td for ptrdiff_t. sizeof produces size_t, whose underlying type is implementation-defined: do not assume unsigned long on every platform. %s expects a pointer to a valid null-terminated character sequence. %p expects void * for an object pointer; its textual representation is implementation-defined. Use <inttypes.h> macros such as PRId64 for int64_t instead of guessing whether it aliases long or long long.
Promotions and printf versus scanf
In variadic calls, float promotes to double, and narrow integer types undergo the integer promotions. Thus printf uses %f for an ordinary float or double expression and %Lf for long double. scanf is different: %f expects float * and %lf expects double * because it writes through pointers. Pointers do not undergo these value promotions. A printf rule must not be copied blindly to scanf.
Fix the type contract, not the symptom
A cast to int may silence a size_t warning but can lose range; %zu preserves the original value. Width and precision supplied using * require int arguments. Never pass untrusted text as the format: use printf("%s", text). Compiler format checking is strongest for literal or otherwise compiler-visible formats. Warnings are diagnostics, not proof that an unchecked dynamic format is safe.
Top Root Causes & Specific Code Fixes
Printing sizeof with %d
sizeof returns size_t; use its standard size modifier rather than assuming a particular machine width.
printf("%d\n", sizeof(int));printf("%zu\n", sizeof(int));Confusing int and long
Use the l modifier for a long value, even on targets where int and long happen to occupy the same number of bytes.
long total = 100000L;
printf("%d\n", total);long total = 100000L;
printf("%ld\n", total);Using an integer conversion for an address
Convert an object pointer to void * for %p. There is no fully portable requirement that a pointer fit in unsigned long.
int value = 7;
printf("%lu\n", &value);int value = 7;
printf("%p\n", (void *)&value);Complete Broken and Corrected Programs
Compare the source before running it. The broken program is intentionally incorrect; its behavior can depend on the compiler and platform.
Read the broken program
#include <stdio.h>
int main(void) {
long count = 42L;
printf("%d\n", count);
return 0;
}Open broken program in compilerRead the corrected program
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void) {
size_t count = 42;
long balance = 100000L;
int64_t ticks = INT64_C(9000000000);
float ratio = 1.5f;
printf("Count: %zu\n", count);
printf("Balance: %ld\n", balance);
printf("Ticks: %" PRId64 "\n", ticks);
printf("Ratio: %.1f\n", ratio);
return 0;
}Open corrected program in compilerExpected output from the corrected program
Reference output, not a live execution result.
Count: 42
Balance: 100000
Ticks: 9000000000
Ratio: 1.5Debugging Techniques and Commands
gcc -std=c17 -Wall -Wextra -Wformat=2 -Werror=format main.c -o app
Make format mismatches fail your local verification rather than shipping a program with undefined behavior.
gcc -std=c17 -Wall -Wextra -Wconversion main.c -o app
Inspect each argument's actual declared type and the API return type; pointer size and a successful run do not validate a format.
Frequently Asked Questions
Why does %d warn for size_t?
%d requests an int. size_t is an unsigned integer type chosen by the implementation; %zu is the portable conversion for it in C99 and later.
Is a format warning harmless if output looks correct?
No. A mismatched printf argument can cause undefined behavior. A single observed output does not validate the call.
Why is %lf different in scanf and printf?
scanf needs %lf for a double pointer and %f for a float pointer. In printf, float promotes to double, so %f prints both; the l modifier on a floating conversion has no effect in modern C printf.
How do I print an address or int64_t portably?
Use %p with an object pointer cast to void *. For int64_t include inttypes.h and concatenate PRId64 into the format string.