3

当这个程序运行时,“stderr”行显示在“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;
}
4

3 回答 3

7

FILE *s stdout 和 stderr 以及文件描述符 1 和 2 之间存在差异。在这种情况下,是 FILE 导致了您未预料到的行为。stderr默认情况下不缓冲,因此在出现错误的情况下,您可以以最可靠的方式打印出消息,即使这种打印的性能会降低程序的整体性能。

stdout,默认情况下是缓冲的。这意味着它有一个内存数组,用于存储您告诉它写入的数据。它一直等到数组(称为缓冲区)填充到某个级别或(如果它设置为行缓冲,它通常是)直到它看到一个'\n'. 不过,你可以打电话fflush(stdout);让它继续打印。

您可以更改 的缓冲设置FILE *man 3 setbuf具有为您执行此操作的功能。

在您的示例中,stdout缓冲区在将“stderr”写入屏幕时保存字符串“stdout”。然后在退出程序时,所有打开FILE *的都被刷新,所以“stdout”然后被打印出来。

于 2010-10-19T19:48:33.760 回答
5

两个流 stdout 和 stderr 可能使用相同的文件描述符,但在 FILE 流将任何数据写入其底层文件描述符之前,数据存储在流的缓冲区中。stdout 和 stderr 中的缓冲区不会因为两个流连接到同一个文件描述符而变得相同。

请注意,此缓冲是由 stdio 库中的 FILE 流完成的,而不是由 OS 内核及其文件描述符完成的。那里可能还有其他缓冲,但这个问题是由上面的 stdio 库级别引起的。

于 2010-10-19T19:46:59.197 回答
4

刷新标准输出怎么样?

dup2(fd[1], fileno(stdout));
dup2(fd[1], fileno(stderr));
close(fd[1]);
fprintf(stdout,"stdout\n");
fflush(stdout);
fprintf(stderr,"stderr\n");

(刚刚尝试过,它有效)

于 2010-10-19T19:39:46.977 回答