6

So I know printf() is higher level than write() and ends up using write(). Printf() is buffered and write() makes system calls.

Example 1, if I were to run a program with printf() before write() then it would output the value of printf() before the value of write().

Example 2, if I were to run the same program and have it go through output redirection into a file, the value of write() outputs before printf().

#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("This is a printf test\n");
    write(STDOUT_FILENO, "This is a write test\n", 21);
    return 0;
}

I don't understand what is happening here. In example 1, is the program waiting for printf()s output before running write()? In example 2, is the program redirecting the first output that is ready? And because write() is lower level, and does not need to buffer like printf() then it is printed first?

1
  • 3
    Look up setvbuf() and the meanings of _IONBF, _IOLBF and _IOFBF. When the output goes to the terminal, you get _IOLBF behaviour; when the output goes to a file, you get _IOFBF behaviour. Commented Feb 29, 2012 at 0:13

3 Answers 3

6

You answered your own question.

printf is buffered and write is not.

For output to a terminal, the C stdio system has a feature that it flushes the buffers whenever it sees a newline '\n'. For more about stdio buffering look at the documentation for setvbuf.

But when output is to a file to increase speed the stdio system does not flush the buffer. That is why write output appears first.

Here is some of the strace output from running on my Linux system:

fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7880b41000
write(1, "This is a printf test\n", 22) = 22
write(1, "This is a write test\n\0", 22) = 22

The fstat is where the stdio system detects the type of output file descriptor 1 is connected to. I believe it looks at st_mode and sees that it is a character device. A disk file would be a block device. The mmap is the memory allocation for the stdio buffer, which is 4K. Then the output is written.

Sign up to request clarification or add additional context in comments.

7 Comments

I feel unclear. Matteo's answer says usually the buffering done by libc is disabled (or a flush is forced at every carriage return). However, your answer says the C stdio system has a feature that it flushes the buffers whenever it sees a newline '\n'. printf always goes into the buffer, correct? It is just whether it gets flushed or not at carriage return?
In the example for the output redirection, is this a memory allocation thing? meaning that while the system is waiting for printf, it runs write first right? For the regular program run, is the C checking for carriage returns before running the next command? I understand the behavior for the output, but how does it works in depth. I hope I was able to convey what I am trying to ask and understand.
@Doug: I believe most implementations separate the output and the buffer handling. So printf knows nothing about the buffering. It calls internal functions that write to the buffer. Then if it is in line-buffer mode those functions check the buffer for a newline. If they find one, that line is sent to the system with write. If it is in fully-buffered mode it only checks for a full buffer, not newlines.
@Doug: It is not a memory allocation thing. Nothing is being waited for, exactly. What happens in fully buffered mode is that the printf output is written into the buffer. Then write is called and the write output is immediately written. Then the program exits. During exit, the buffer is flushed and written out.
@Doug: Not a stack. A stack would make it output in reverse order. The output buffer is FIFO. First In, First Out.
|
3

This has to do with output buffering done by the C standard library. In the first case, since you are writing on the terminal, the buffering done by libc is line-oriented (a flush is forced at every carriage return), to show immediately on screen the text, privileging interactivity over performance (which shouldn't be an issue, since terminals aren't expected to be the target for loads of text). Because of this, the printf output is written immediately with some write call, which happens before the next one you make explicitly.

In the second case, libc detects that you're writing on a file, so, to enhance the performance, it enables buffering; because of this, usually the first printf won't immediately be committed, and your write will happen before libc actually flushes the buffer.

Again, this is what usually happens. I don't think this kind of behavior is mandated by any standard (edit: actually, this is mandated by C99, see @Jonathan's comment) (and in the second example, even with buffering enabled, the library may decide to do a flush anyway, e.g. if the buffer gets filled by your printf).

2 Comments

The behaviour is mandated by the standard. In C99, §7.19.3, ¶3 When a stream is fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled. When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. and ¶7 As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
@JonathanLeffler: uh, good to know, I didn't found that because I was looking for "terminal" instead of "interactive device". I fixed my answer.
0

Internally printf will use write when its buffer is full. It may also do a write before the buffer is full if it detects it is writing to an interactive output such as stdout that hasn't been redirected.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.