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;
}
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.