Reputation: 81
When this program is run, the "stderr" line is displayed before the "stdout" line. Why? I thought dup2 would make stderr and stdout use the same file descriptor so there should be no problem with buffering. I'm using gcc 3.4.6 on Solaris 10.
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd[2];
int pid;
char buf[256];
int n;
if(pipe(fd) < 0) {
perror("pipe");
return 1;
}
if((pid = fork()) < 0) {
perror("fork");
return 1;
}
else if(pid > 0) { // parent
close(fd[1]);
if((n = read(fd[0], buf, sizeof(buf))) > 0) {
buf[n] = 0;
printf("%s", buf);
}
}
else {
dup2(fd[1], fileno(stdout));
dup2(fd[1], fileno(stderr));
close(fd[1]);
fprintf(stdout,"stdout\n");
fprintf(stderr,"stderr\n");
}
return 0;
}
Upvotes: 3
Views: 13305
Reputation: 12382
There is a difference between the FILE *
s stdout and stderr and the file descriptors 1 and 2. In this case it is the FILEs that are causing the behavior that you weren't expecting. stderr
is not buffered by default so that in the case of an error you can print out the message in the most reliable manner, even though the performance of this printing slows down overall performance of the program.
stdout
, by default, is buffered. This means that it has an array of memory that it is storing the data that you told it to write in. It waits until it has the array (called a buffer) filled to a certain level or (if it is setup for line buffering, which it often is) until it sees a '\n'
. You could call fflush(stdout);
to make it go ahead and print, though.
You can change the buffering settings of FILE *
. man 3 setbuf
has the functions that do this for you.
In your example the stdout
buffer was holding the string "stdout" while the "stderr" was being written to the screen. Then upon exiting the program all of the open FILE *
are flushed, so "stdout" then got printed.
Upvotes: 7
Reputation: 27632
The two streams stdout and stderr may be using the same file descriptor, but before a FILE stream writes any data to its underlying file descriptor, the data is stored in the stream's buffer. The buffers in stdout and stderr don't become the same just because the two streams are connected to the same file descriptor.
Note that this buffering is done by the FILE streams in the stdio library, not by the OS kernel and its file descriptors. There may be other buffering going on there too, but this problem is caused by the stdio library level above.
Upvotes: 5
Reputation: 133567
What about flushing stdout?
dup2(fd[1], fileno(stdout));
dup2(fd[1], fileno(stderr));
close(fd[1]);
fprintf(stdout,"stdout\n");
fflush(stdout);
fprintf(stderr,"stderr\n");
(just tried and it works)
Upvotes: 4