Reputation: 145
These days I was learning the "apue", a result of an typical case confused me. The following are the sample codes of "sample.c":
#include "apue.h"
#include <stdio.h>
#define BUFF_SZ 4096
int main()
{
int n = 0;
char buff[BUFF_SZ] = {'\0'};
while ((n = read(STDIN_FILENO, buff, BUFF_SZ)) > 0) {
printf("read %d bytes\n", n);
if (write(STDOUT_FILENO, buff, n) != n) {
err_sys("write error");
}
}
if (n < 0) {
err_sys("read error");
}
return 0;
}
After compilation gcc sample.c
, you can use this command echo Hello | ./a.out
and get the following std output on terminal:
read 6 bytes
Hello
However, if you redirect the output to a file echo Hello | ./a.out > outfile
, then use cat outfile
to see the content:
Hello
read 6 bytes
The ouput changes order after redirection! I wonder if some one could tell me the reason?
Upvotes: 3
Views: 114
Reputation: 326
The problem is that the writes are handled by write(2)
call, so you effectively lose control of what happens.
If we look at the documentation for write(2) we can see that the writes are not guaranteed to be actually written until a read()
occurs. More specifically:
A successful return from write() does not make any guarantee that data has
been committed to disk. In fact, on some buggy implementations, it does not even
guarantee that space has successfully been reserved for the data. The only way to
be sure is to call fsync(2) after you are done writing all your data.
This means that depending on the implementation and buffering of the write(2)
(which may differ even between redirects and printing to screen), you can get different results.
Upvotes: 0
Reputation: 36597
printf()
, by default, buffers its output, while write()
does not, and there is no synchronisation between then.
So, in your code, it is possible that printf()
stores its data in a buffer and returns, then write()
is called, and - as main()
returns, printf()
s buffer is flushed so that buffered output appears. From your description, that is happening when output is redirected.
It is also possible that printf()
writes data immediately, then write()
is called. From your description, that happens when output is not redirected.
Typically, one part of redirection of a stream is changing the buffer - and therefore the behaviour when buffering - for streams like stdout
and stdin
. The precise change depends on what type of redirection is happening (e.g. to a file, to a pipe, to a different display device, etc).
Imagine that printf()
writes data to a buffer and, when flushing that buffer, uses write()
to produce output. That means all overt calls of write()
will have their output produced immediately, but data that is buffered may be printed out of order.
Upvotes: 2
Reputation: 122383
For the standard I/O function printf
, when you output to a terminal, the standard output is by default line buffered.
printf("read %d bytes\n", n);
\n
here cause the output to flush.
However, when you output to a file, it's by default fully buffered. The output won't flush unless the buffer is full, or you explicitly flush it.
The low level system call write
, on the other hand, is unbuffered.
In general, intermixing standard I/O calls with system calls is not advised.
Upvotes: 4