在C中自动刷新stdout缓冲区的规则是什么?

我只是好奇应该满足哪些条件来自动刷新stdout缓冲区。

首先,我很困惑这个伪代码不会在每次迭代时打印输出:

while (1) { printf("Any text"); sleep(1); } 

但如果我添加换行符,它会。

经过几次实验,我发现在我的机器上stdout缓冲区被刷新:

  1. 当我输入1025个或更多字符时;
  2. 当我读到标准时;
  3. 当我把换行符添加到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提供更方便的界面。

printfscanfgetcharfputs和其他FILE *函数都是委托给write()read()的第3部分函数,​​它们是第2部分的函数。 read()write()不缓冲。 printf()FILE结构中的缓冲区交互,偶尔决定通过write()发送该缓冲区的内容。

  • 每当输出换行时,都应刷新行缓冲的输出流。

  • 每当从任何行缓冲的输入流尝试读取时,实现可以(但不是必须)刷新所有行缓冲的输出流。

  • 除非可以确定它们不与“交互设备”相关联,否则不允许实现默认使流完全缓冲。 因此,当stdin / stdout是终端时,它们不能完全缓冲,只能进行行缓冲(或无缓冲)。

如果您只需要在输出到终端时进行刷新,则可以假设写入换行符会导致刷新。 否则你应该在需要刷新的地方明确调用fflush

在许多情况下,流上的缓冲输出会自动刷新:

  1. 当您尝试输出并且输出缓冲区已满时。
  2. 当流关闭时。
  3. 当程序通过调用exit终止时。
  4. 写入换行符时,如果流是行缓冲的。
  5. 每当任何流上的输入操作实际上从其文件中读取数据时。

默认情况下, stdout是行缓冲的。

如果要在其他时间刷新缓冲输出,可以调用fflush。

在线C2011标准

7.21.3文件

3当流未缓冲时 ,字符应尽快从源或目标出现。 否则,可以将字符作为块累积并发送到主机环境或从主机环境发送。 当流被完全缓冲时 ,当填充缓冲区时,字符旨在作为块传输到主机环境或从主机环境传输。 当流被行缓冲时 ,当遇到换行符时 ,字符将作为块传输到主机环境或从主机环境传输。 此外,当填充缓冲区,在无缓冲流上请求输入时,或者在需要从主机环境传输字符的行缓冲流上请求输入时,字符旨在作为块传输到主机环境。 。 对这些特性的支持是实现定义的,可能会受到setbufsetvbuf函数的影响。

7在程序启动时,预定义了三个文本流,无需明确打开 – 标准输入 (用于读取传统输入), 标准输出 (用于写入常规输出)和标准错误 (用于写入诊断输出)。 最初打开时,标准错误流未完全缓冲; 当且仅当可以确定流不参考交互设备时,标准输入和标准输出流是完全缓冲的。

因此,行缓冲流将在换行符上刷新。 在我经验丰富的大多数系统上, stdout在交互式会话中进行行缓冲。