The prototype for the printf
function is
int printf(const char * restrict format, ...);
The first argument is always a text string that describes the format of the output (hence why you can't just write printf(fruit);
). The ...
indicates that printf
may take zero or more additional arguments after the format string (this is known as a variadic function).
Unfortunately, variadic functions don't automatically know the number or types of arguments passed to them in the variable part of the argument list; they just see a starting address for the next available argument after the last fixed argument. You somehow have to pass that information as part of the fixed arguments. With printf
, the number and types of additional arguments are indicated by conversion specifiers in the format string. So when you write
printf("%f\n", fruit);
the conversion specifier %f
tells printf
that there's one additional argument of type double
following the format string. The conversion specifier also tells printf
how the value should be formatted for display. For example, in
printf("%7.2f\n", fruit);
the conversion specifier %7.2f
tells printf
to display the value as a 7-character wide field with 2 digits following the decimal point, or 9999.99
.
If the type of the argument doesn't match the conversion specifier, the behavior is undefined. For example, if you write
printf("%d\n", fruit);
you're telling printf
to expect an int
when you're really passing it a double
, which is a logic error. Depending on the underlying architecture any number of different things may happen, so the behavior is left undefined and the compiler doesn't have to do anything in particular about it; any result is considered "correct". Really nice compilers will issue a diagnostic that the argument doesn't match the conversion specifier. Most will simply translate the code as-is, and the result can be anything from unexpected output to an access violation.
Similarly, if you don't pass enough arguments to match the number of conversion specifiers, the behavior is undefined:
printf("%f %d\n", fruit);
If you pass more arguments than conversion specifiers, the additional arguments are evaluated, but otherwise ignored:
printf("%f\n", fruit, apples, bananas);