printf(3)
C library function
Writes formatted text to standard output. The formats to know (%d, %ld, %zu, %p, %s), what printf returns and the -Wformat warnings.
#include <stdio.h>
int printf(const char *restrict format, ...);Description
printf walks through its format one character at a time. Ordinary text is copied as is; each % starts a conversion, which consumes the next argument and writes it out as text. Since printf takes a variable number of arguments, it does not know their types: the format tells it, and the format has to match exactly.
| Format | Expected argument |
|---|---|
%d or %i | int |
%u, %x | unsigned int, in decimal or in hexadecimal |
%ld, %lld | long, long long |
%zu | size_t, the type of sizeof and of strlen |
%f | double, or a float, converted to double at the call |
%c | a character, passed as an int |
%s | a char * to a string terminated by '\0' |
%p | a void * |
%% | nothing, prints a % |
The text does not go straight to the screen: it goes through the stdout buffer, which is flushed at every \n on a terminal and in blocks on a pipe. That is why printf prints nothing before a crash.
Return value
The number of bytes written, or a negative value on error. Bytes, not characters: in a UTF-8 source file, printf("café\n") returns 6, because the “é” takes two bytes.
Pitfalls
A format that does not match the type is undefined behavior.
-Wallturns on-Wformat, which catches it at compile time. For asizeof, GCC suggests%ldbecausesize_tis anunsigned longon this machine, but%zuis the only portable way to write it:
$ gcc -Wall -Wextra -g warn.c -o warnwarn.c: In function 'main':warn.c:7:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Wformat=] 7 | printf("%d\n", sizeof scores); | ~^ ~~~~~~~~~~~~~ | | | | int long unsigned int | %ldprintf(text), whentextcomes from the user, interprets every%it contains, and%neven lets it write to memory. Writeprintf("%s", text).%pexpects avoid *: convert the pointer,(void *)p.The fix-the-format exercise has you fix a wrong format under
-Werror, with asize_tand along.
Example
#include <stdio.h>
int main(void){ int scores[5] = {12, 15, 9, 18, 11}; long total = 6000000000L; int n;
n = printf("Yasmine is %d years old\n", 19); printf("%d bytes\n", n); n = printf("café\n"); printf("%d bytes\n", n); printf("%zu bytes at address %p\n", sizeof scores, (void *)scores); printf("total: %ld\n", total); return 0;}$ gcc -Wall -Wextra -g formats.c -o formats$ ./formatsYasmine is 19 years old24 bytescafé6 bytes20 bytes at address 0xffffefc7e410total: 6000000000The \n counts toward the 24 bytes of the first line. The address changes on every run.
mini_printf
Write mini_printf, which expands %c, %s, %d, %x and %% with write and returns the exact number of bytes written.