I/O Buffering
When you call printf, the text doesn't necessarily appear on the screen the instant the function returns. The standard I/O library (stdio) typically collects output in an internal memory buffer first, and only actually sends it to the terminal, file, or pipe once that buffer fills up, gets explicitly flushed, or the program exits normally. This is buffering, and it exists purely for performance — writing data in larger chunks is far cheaper than performing a system call for every single character.
The three buffering modes
Mode | When output is flushed | Typical default for |
|---|---|---|
Unbuffered | Immediately, after every write |
|
Line-buffered | Whenever a newline | A terminal (interactive |
Fully buffered | Only when the buffer fills up, or on an explicit flush | A regular file or a pipe (non-interactive |
Notice that stdout's behavior actually depends on where its output is going — the exact same printf calls can behave differently depending on whether you run the program directly in a terminal (line-buffered) or redirect its output to a file, like ./program > output.txt (fully buffered).
Forcing output with fflush
fflush(stream) forces any buffered data for that stream to be written out immediately. This matters most when you're about to do something slow (waiting for user input, sleeping, or performing a blocking operation) right after a printf that hasn't hit a newline yet:
#include <stdio.h>
int main(void) {
printf("Processing"); /* no trailing newline -- may sit in the buffer */
fflush(stdout); /* force it to appear right now */
for (int i = 0; i < 3; i++) {
/* imagine some slow work happening here */
printf(".");
fflush(stdout);
}
printf(" done!\n");
return 0;
}Without the fflush calls, a fully buffered stdout (for example, when the program's output is redirected to a file) might not show anything at all until the whole loop finishes and the buffer is flushed as a block.
Why mixing printf with lower-level writes can reorder output
printf writes go through stdio's buffer, but a lower-level call like POSIX write() bypasses that buffer entirely and sends bytes straight to the operating system. If you mix the two on the same file descriptor, the write() output can show up before buffered printf output that was actually issued first, simply because the printf data was still sitting in the buffer when write() fired:
#include <stdio.h>
#include <unistd.h>
int main(void) {
printf("A: from printf (buffered)"); /* no newline yet -- may be held back */
write(1, "B: from write (unbuffered)\n", 27); /* goes out immediately */
printf("\n");
return 0;
}
/* Depending on buffering, "B" can appear on screen before "A",
even though the printf("A: ...") call happened first in the source. */