使用dup2,stdout和stderr时出现问题

时间:2010-10-19 19:36:44

标签: c fork stdout stdin 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;
}

3 个答案:

答案 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");

(刚刚试过并且有效)