为什么在写入stderr之前我需要在stdout上使用fflush?

时间:2017-03-08 00:08:31

标签: c unix stdout stderr fflush

我正在阅读' UNIX网络编程:套接字网络API'在示例代码中,它们具有错误处理功能,其中包含以下行:

fflush(stdout);     /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);

其中buf包含错误说明。我不明白为什么在第一行的stdout上使用fflush以及为什么评论解释了它的使用原因。

2 个答案:

答案 0 :(得分:11)

这是因为缓冲。 Stdout and stderr are usually buffered differently。 Stdout 通常行缓冲,这意味着它在看到换行符之前不会显示输出。 Stderr 通常无缓冲,会立即打印出来,你应该看到错误信息。

但他们都去了同一个地方,终点站。这就是/* in case stdout and stderr are the same */的含义。他们通常是。但由于它们的缓冲方式不同,这可能导致它们无序显示。

考虑这段代码。请注意缺少换行符。

#include <stdio.h>

int main() {
    fprintf(stdout, "This is to stdout. ");
    fprintf(stderr, "This is to stderr. ");
    fprintf(stdout, "This is also to stdout. ");
}

您希望输出为:

This is to stdout. This is to stderr. This is also to stdout.

但它不是。它没有问题。

$ ./test
This is to stderr. This is to stdout. This is also to stdout.

立即显示输出到stderr,它是无缓冲的。虽然stdout必须等到stdout缓冲区被换行符刷新。没有换行符,因此在程序退出时会刷新。

通过在使用stderr之前刷新stdout,无论缓冲如何,都要确保输出的顺序正确。

#include <stdio.h>
#include <unistd.h>

int main() {
    fprintf(stdout, "This is to stdout. ");
    fflush(stdout);
    fprintf(stderr, "This is to stderr. ");
    fprintf(stdout, "This is also to stdout. ");
}

$ ./test
This is to stdout. This is to stderr. This is also to stdout. 

这可确保错误消息与正常消息一起以正确的顺序出现。这避免了对什么错误消息适用于程序的哪个部分的混淆。

答案 1 :(得分:2)

如果stdout和stderr指向同一个文件,则必须确保首先写入stdout缓冲区中的任何内容。