我刚刚学习了 C 中的流缓冲。据我所知,C 中的 printf() 是缓冲的,只有当遇到新行、缓冲区已满或我们手动刷新 stdout 时才会打印。然后我尝试
我刚刚学习了 C 中的流缓冲。据我所知, printf() C 中的流缓冲是缓冲的,只有当它遇到新行、缓冲区已满或我们 stdout 手动刷新时才会打印。然后我尝试了以下几行代码:
printf()
stdout
#include <stdio.h> int main() { printf("Hello world"); while(1); }
理论上,控制台不会收到任何内容,因为 Hello world 仍在缓冲区中。但由于某些原因,我的控制台仍然显示此字符串。为什么会这样?
Hello world
编辑 :我正在使用 Windows 10 中的命令提示符。
我在 Debian Linux 中测试了您的程序,根本没有看到任何输出。在使用 MinTTY 的 MSYS2(Windows)中,我只有在使用 Ctrl+C 终止程序后才看到输出。您在哪里测试这个程序?有时刷新行为取决于标准输出是连接到终端还是文件。
@RyanZhang 提供的链接回答了“为什么应用程序退出时会刷新缓冲区”:“当同一设备上即将发生输入时,必须刷新缓冲区”或“当相关文件关闭时,缓冲区也会刷新”。但似乎在 OP 的示例中,在没有输入的情况下,应用程序退出之前会打印换行符。
正确,我应该说“使用 gcc”而不是“在 Linux 上”,这就像使用品牌名称而不是产品一样,只是习惯而已(gcc 在 Linux 上很常见,而 Microsoft 编译器在 Windows 上很常见)。@NguyễnTùngDương 互联网上有很多相互矛盾或不完整的信息,这就是为什么我想知道官方标准对此有何规定,既然你问了这个问题,最好能添加它。似乎 chux 的回答说它依赖于实现,这正是我所怀疑的。
printf() 在 C 中,它被缓冲,并且只有当遇到新行时才会打印
不完全是。
流通常有以下三种模式: 无缓冲 , 全缓冲 , 行缓冲 。通常 stdout 是 行缓冲的 ,当打印 时刷新数据 '\n' ,其内部缓冲区已满或由于显式命令,例如 fflush(stdout) .
'\n'
fflush(stdout)
然而 C 对这 3 种模式有具体说明: 对这些特性的支持是由实现定义的 。C17dr § 7.21.3 3.
因此,看到输出和看不到输出都符合 OP 的代码。
为了确保输出可见,请刷新。否则,请遵循实现定义的行为。
printf("Hello world"); fflush(stdout); // add while(1);
我不确定您正在阅读 C 标准的哪一部分,但根据 Microsoft 的 C 运行时库 文档
使用流例程打开的文件默认是缓冲的。stdout 和 stderr 函数在已满时会被刷新,或者, 如果你正在写入字符设备,则在每次调用库之后刷新 .
该文档还链接到 Microsoft 特定的 setvbuf 函数,您可以根据需要使用该函数来控制缓冲。我通常只让运行时库使用其默认设置,然后 fflush(stdout) 在每个我想要确保输出被刷新的地方显式调用。
setvbuf
@DavidGrayson 很好的引用,但是 while(1); 看起来不像是“库调用”,这是否意味着每次调用 printf 时都会有一个隐式的 fflush?
@DavidRanieri — 是的,这解释了为什么在 Windows 上工作的人们认为输出末尾的换行符是没有必要的。
此答案中的链接是引用它的文档。微软的意思是,每次调用 printf()(库调用)时,本质上都是写入“字符设备”,即控制台 (stdout),都会立即刷新,即显示在终端上。所以您看到的内容与文档相符。