在这个程序中,输出是无序的,当stdout
链接到端子时,包含stdout
的fprintf()
的输出被写入端子,但为什么包含stderr
的fprintf()
的输出也打印到端子?相反,它应该打印到stderr
文件句柄。stderr
是否也链接到终端?
代码
#include <stdio.h>
#include <unistd.h>
int main() {
fprintf(stdout, "This is to stdout. ");
fprintf(stderr, "This is to stderr. ");
fprintf(stdout, "This is also to stdout. ");
return 0;
}
OUTPUT(在线编译器中)
This is to stderr. This is to stdout. This is also to stdout.
我也想问一件事。为什么我的Visual Studio Code IDE
中的输出不同。
VS代码输出
This is to stdout. This is to stderr. This is also to stdout.
这里VS CODE给出了来自在线编译器的不同输出。为什么会这样,如何解决?
在C实现中,当输出到终端时,stdout
是行缓冲的,而stderr
是非缓冲的。这意味着stderr
的输出立即发送到终端,而stdout
的输出仅在以下情况下发送:
- 发送一个新行字符
- 从用户1请求输入(因此在用户应该键入响应之前将出现在CCD_ 13上发送的提示)
- 缓冲区已满,或者
- 请求缓冲器刷新(如同
fflush
)
缓冲流时,字符可能会累积在缓冲区中,并在缓冲区满时作为块发送或接收。之所以使用缓冲区,是因为发送或接收数据的操作有很大的开销,因此对发送的每个字符或每个部分行执行这些操作在执行时间和精力等资源方面会很昂贵。在一次操作中从缓冲区发送多个字符更有效。
除了非缓冲区和行缓冲区外,还有完全缓冲,其中只有当缓冲区已满时才发送或接收字符。C标准在C 2018 7.21.3 3中描述了缓冲。
在7.21.37中,标准告诉我们标准错误流没有被完全缓冲。它可以是无缓冲的,也可以是行缓冲的。您的C实现显然选择了不缓冲,因此错误消息将立即写入终端。这段话还告诉我们,只有当流"可以确定不指向交互式设备"时,标准输入和标准输出才会被完全缓冲。例如,如果将输出重定向到文件而不是终端,则它不指向交互式设备,并且应该被完全缓存。当已知输出将进入交互式设备时,不应对其进行完全缓冲。它可能是行缓冲的,也可能是非缓冲的,而您的C实现显然选择了行缓冲。
如果您修改程序以在它打印的每个字符串的末尾包含n
,您将按顺序看到它们,因为无缓冲流和行缓冲流将按顺序打印每个完整的行(以换行符结尾的字符)。
您还可以使用setvbuf
在流打开后和对其执行任何其他操作之前更改流的缓冲模式。例如,要将stdout
设置为无缓冲,您可以使用:
int result = setvbuf(stdout, NULL, _IONBF, 0);
if (result != 0)
fprintf(stderr, "Error, setvbuf returned %d.n", result);
setvbuf
在C 2018 7.21.5.6中有规定。_IOFBF
请求完全缓冲,_IOLBF
请求行缓冲。(第二个和第四个参数用于提供您自己的数组作为缓冲区及其长度。)
脚注
1具体而言,在未缓冲流或"需要从主机环境传输字符"的行缓冲流上请求输入(如通过调用fgetc
或scanf
)将触发行缓冲输出的刷新。
@Eric告诉我我的答案是错误的(
Stdout和stderr在逻辑上不同。可以将它们重定向到不同的设备,如打印机和屏幕。指令序列必须遵循程序中分号所暗示的顺序。因此,第一个字符串被发送到stdout。之后,第二个字符串被发送到stderr。之后,第三个字符串被发送到stdout。
如果您将字符串发送到屏幕和打印机,字符串将被发送到各自的端口,但这些设备在进行各自打印时所用的时间是独立的,并且超出了程序的控制范围。以打印机有挂起的工作为例。
但是,默认情况下,stderr和stdout指向同一个设备:屏幕。这个事实并不意味着字符串必须按顺序显示。操作系统可能会以不同的方式处理stderr和stdout上的打印请求。字符串在逻辑上被发送到不同的设备,这些设备在物理上产生了相同的结果,但由于某种原因,操作系统可能会优先考虑stderr
stderr流用于通知错误消息
这是一个特殊而危急的情况。这样做的目的是让文本尽快到达,这样字符就不会被缓冲,而是在到达后立即发送
另一方面,发送到stdout的文本是缓冲的,这样聊天者就可以分块或整行发送。如果操作系统检测到一个文本被发送到stderr,也许它会优先考虑它
解决方案是只有在发生严重错误时才使用stderr。