dup2、stdout 和 stderr 出现问题
当该程序运行时,“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;
}
When this program is run, the "stderr" line is displayed before the "stdout" line. Why? I thought dup2 would make stderr and stdout use the same file descriptor so there should be no problem with buffering. I'm using gcc 3.4.6 on Solaris 10.
#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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
FILE *
的 stdout 和 stderr 以及文件描述符 1 和 2 之间存在差异。在本例中,是 FILE 导致了您不期望的行为。默认情况下,stderr
不会进行缓冲,因此在发生错误时,您可以以最可靠的方式打印出消息,即使这种打印的性能会降低程序的整体性能。stdout
默认情况下是缓冲的。这意味着它有一个内存数组,用于存储您告诉它写入的数据。它会等待,直到数组(称为缓冲区)填充到一定水平或(如果它设置为行缓冲,通常是这样)直到它看到'\n'
。不过,您可以调用 fflush(stdout); 来使其继续并打印。您可以更改
FILE *
的缓冲设置。man 3 setbuf
具有为您执行此操作的函数。在您的示例中,
stdout
缓冲区在将“stderr”写入屏幕时保存字符串“stdout”。然后退出程序后,所有打开的 FILE * 都会被刷新,因此“stdout”会被打印出来。There is a difference between the
FILE *
s stdout and stderr and the file descriptors 1 and 2. In this case it is the FILEs that are causing the behavior that you weren't expecting.stderr
is not buffered by default so that in the case of an error you can print out the message in the most reliable manner, even though the performance of this printing slows down overall performance of the program.stdout
, by default, is buffered. This means that it has an array of memory that it is storing the data that you told it to write in. It waits until it has the array (called a buffer) filled to a certain level or (if it is setup for line buffering, which it often is) until it sees a'\n'
. You could callfflush(stdout);
to make it go ahead and print, though.You can change the buffering settings of
FILE *
.man 3 setbuf
has the functions that do this for you.In your example the
stdout
buffer was holding the string "stdout" while the "stderr" was being written to the screen. Then upon exiting the program all of the openFILE *
are flushed, so "stdout" then got printed.两个流 stdout 和 stderr 可能使用相同的文件描述符,但在 FILE 流将任何数据写入其底层文件描述符之前,数据将存储在流的缓冲区中。 stdout 和 stderr 中的缓冲区不会仅仅因为两个流连接到相同的文件描述符而变得相同。
请注意,此缓冲是由 stdio 库中的 FILE 流完成的,而不是由操作系统内核及其文件描述符完成的。那里可能还有其他缓冲,但这个问题是由上面的 stdio 库级别引起的。
The two streams stdout and stderr may be using the same file descriptor, but before a FILE stream writes any data to its underlying file descriptor, the data is stored in the stream's buffer. The buffers in stdout and stderr don't become the same just because the two streams are connected to the same file descriptor.
Note that this buffering is done by the FILE streams in the stdio library, not by the OS kernel and its file descriptors. There may be other buffering going on there too, but this problem is caused by the stdio library level above.
刷新标准输出怎么样?
(刚刚尝试过并且有效)
What about flushing stdout?
(just tried and it works)