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

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)

nat*_*ose 7

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

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

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

在您的示例中,stdout缓冲区持有字符串"stdout",而"stderr"正在写入屏幕.然后在退出程序时,所有打开的FILE *都被刷新,所以"stdout"然后打印出来.


Tho*_*thy 5

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

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