运行此程序时,“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;
}
答案 0 :(得分:7)
FILE *
sddout和stderr以及文件描述符1和2之间存在差异。在这种情况下,导致您不期望的行为的是FILE。默认情况下,stderr
不会被缓冲,因此在出现错误的情况下,您可以以最可靠的方式打印出消息,即使此打印的性能会降低程序的整体性能。
stdout
是缓冲的。这意味着它有一个内存数组,它存储你告诉它写入的数据。它等待直到它将数组(称为缓冲区)填充到某个级别或(如果它设置为行缓冲,通常是这样)直到它看到'\n'
。你可以打电话给fflush(stdout);
让它继续打印。
您可以更改FILE *
的缓冲设置。 man 3 setbuf
具有为您执行此操作的功能。
在您的示例中,stdout
缓冲区保持字符串“stdout”,而“stderr”正在写入屏幕。然后在退出程序时,所有打开的FILE *
都被刷新,所以“stdout”然后被打印出来。
答案 1 :(得分:4)
两个流stdout和stderr可能正在使用相同的文件描述符,但在FILE流将任何数据写入其底层文件描述符之前,数据存储在流的缓冲区中。 stdout和stderr中的缓冲区不会因为两个流连接到同一个文件描述符而变得相同。
请注意,此缓冲由stdio库中的FILE流完成,而不是由OS内核及其文件描述符完成。可能还有其他缓冲,但这个问题是由上面的stdio库级引起的。
答案 2 :(得分:3)
冲洗stdout怎么样?
dup2(fd[1], fileno(stdout));
dup2(fd[1], fileno(stderr));
close(fd[1]);
fprintf(stdout,"stdout\n");
fflush(stdout);
fprintf(stderr,"stderr\n");
(刚刚试过并且有效)