在C中自动刷新stdout缓冲区的规则是什么?
我只是好奇应该满足哪些条件来自动刷新stdout缓冲区。
首先,我很困惑这个伪代码不会在每次迭代时打印输出:
while (1) { printf("Any text"); sleep(1); }
但如果我添加换行符,它会。
经过几次实验,我发现在我的机器上stdout缓冲区被刷新:
- 当我输入1025个或更多字符时;
- 当我读到标准时;
- 当我把换行符添加到stdout时;
第一个条件是完全清楚的 – 当缓冲区已满时,应该刷新它。 第二个也是合理的。 但为什么换行符导致潮红? 其他隐含条件是什么?
自动刷新标准输出缓冲区的规则是实现定义的 (ID)。 当流是无缓冲 , 完全缓冲或行缓冲时,它是ID。
当流是无缓冲的时 ,字符应尽快从源或目的地出现。 否则,可以将字符作为块累积并发送到主机环境或从主机环境发送。
当流被完全缓冲时 ,当填充缓冲区时,字符旨在作为块传输到主机环境或从主机环境传输。
当流被行缓冲时 ,当遇到换行符时 ,字符将作为块传输到主机环境或从主机环境传输。 此外,当填充缓冲区,在无缓冲流上请求输入时,或者在需要从主机环境传输字符的行缓冲流上请求输入时,字符旨在作为块传输到主机环境。 。
对这些特性的支持是实现定义的 ,……C11dr§7.21.33
我只是好奇应该满足哪些条件来自动刷新stdout缓冲区。
如果代码想确保输出肯定是刷新的,请使用fflush()
。 可以自动刷新流的其他条件是实现定义的。
请参见setbuf(3)
的手册页 。 默认情况下, stdout
设置为行缓冲模式。
printf()
及其变体使用缓冲输出,并委托write()
。 因此,此缓冲由printf
的C库实现控制,缓冲区和缓冲区设置位于FILE
结构中。
同样值得注意的是unix手册页的第3节和第2节之间的区别。 第2节由直接与操作系统通信的函数调用组成,并执行从纯用户程序无法执行的操作。 第3节由用户可以自己复制的函数调用组成,这些函数调用通常委托给第2节调用。 第2节函数包含允许C程序与外部世界交互并执行I / O的低级“魔术”。 第3节function可以为第2节function提供更方便的界面。
printf
, scanf
, getchar
, fputs
和其他FILE *
函数都是委托给write()
和read()
的第3部分函数,它们是第2部分的函数。 read()
和write()
不缓冲。 printf()
与FILE
结构中的缓冲区交互,偶尔决定通过write()
发送该缓冲区的内容。
-
每当输出换行时,都应刷新行缓冲的输出流。
-
每当从任何行缓冲的输入流尝试读取时,实现可以(但不是必须)刷新所有行缓冲的输出流。
-
除非可以确定它们不与“交互设备”相关联,否则不允许实现默认使流完全缓冲。 因此,当stdin / stdout是终端时,它们不能完全缓冲,只能进行行缓冲(或无缓冲)。
如果您只需要在输出到终端时进行刷新,则可以假设写入换行符会导致刷新。 否则你应该在需要刷新的地方明确调用fflush
。
在许多情况下,流上的缓冲输出会自动刷新:
- 当您尝试输出并且输出缓冲区已满时。
- 当流关闭时。
- 当程序通过调用exit终止时。
- 写入换行符时,如果流是行缓冲的。
- 每当任何流上的输入操作实际上从其文件中读取数据时。
默认情况下, stdout
是行缓冲的。
如果要在其他时间刷新缓冲输出,可以调用fflush。
在线C2011标准
7.21.3文件
…
3当流未缓冲时 ,字符应尽快从源或目标出现。 否则,可以将字符作为块累积并发送到主机环境或从主机环境发送。 当流被完全缓冲时 ,当填充缓冲区时,字符旨在作为块传输到主机环境或从主机环境传输。 当流被行缓冲时 ,当遇到换行符时 ,字符将作为块传输到主机环境或从主机环境传输。 此外,当填充缓冲区,在无缓冲流上请求输入时,或者在需要从主机环境传输字符的行缓冲流上请求输入时,字符旨在作为块传输到主机环境。 。 对这些特性的支持是实现定义的,可能会受到setbuf
和setvbuf
函数的影响。
…
7在程序启动时,预定义了三个文本流,无需明确打开 – 标准输入 (用于读取传统输入), 标准输出 (用于写入常规输出)和标准错误 (用于写入诊断输出)。 最初打开时,标准错误流未完全缓冲; 当且仅当可以确定流不参考交互设备时,标准输入和标准输出流是完全缓冲的。
因此,行缓冲流将在换行符上刷新。 在我经验丰富的大多数系统上, stdout
在交互式会话中进行行缓冲。