Dou*_*son 2 c stdin fork stdout dup2
运行此程序时,"stdr"行显示在"stdout"行之前.为什么?我认为dup2会使stderr和stdout使用相同的文件描述符,所以缓冲应该没有问题.我在Solaris 10上使用gcc 3.4.6.
#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;
}
Run Code Online (Sandbox Code Playgroud)
FILE *s stdout和stderr以及文件描述符1和2 之间存在差异.在这种情况下,导致您不期望的行为的是FILE. stderr默认情况下不缓冲,因此在出现错误的情况下,您可以以最可靠的方式打印出消息,即使此打印的性能会降低程序的整体性能.
stdout默认情况下,缓冲.这意味着它有一个内存数组,它存储你告诉它写入的数据.它等待直到它将数组(称为缓冲区)填充到某个级别或(如果它设置为行缓冲,它经常是这样的,直到它看到一个'\n'.不过,你可以打电话fflush(stdout);让它继续打印.
您可以更改缓冲设置FILE *. man 3 setbuf具有为您执行此操作的功能.
在您的示例中,stdout缓冲区持有字符串"stdout",而"stderr"正在写入屏幕.然后在退出程序时,所有打开的FILE *都被刷新,所以"stdout"然后打印出来.
两个流stdout和stderr可能使用相同的文件描述符,但是在FILE流将任何数据写入其基础文件描述符之前,该数据将存储在该流的缓冲区中。只是因为两个流连接到同一文件描述符,stdout和stderr中的缓冲区才变得不同。
请注意,此缓冲是由stdio库中的FILE流完成的,而不是由OS内核及其文件描述符完成的。那里可能还会有其他缓冲,但是此问题是由上面的stdio库级别引起的。