C 中自动 stdout 缓冲区刷新的规则是什么?
What are the rules of automatic stdout buffer flushing in C?
我只是好奇要满足哪些条件才能自动刷新 stdout 缓冲区。
首先,我很困惑这个伪代码不会在每次迭代时打印输出:
while (1) {
printf("Any text");
sleep(1);
}
但如果我添加换行符,它就会。
经过几次实验,我发现我机器上的标准输出缓冲区被刷新了:
- 当我向标准输出输入 1025 个或更多字符时;
- 当我读取标准输入时;
- 当我将换行符放入标准输出时;
第一个条件完全清楚 - 当缓冲区已满时,应该将其刷新。第二个也是有道理的。但是为什么换行符会导致刷新?其他隐含条件是什么?
每当输出换行符时,应刷新行缓冲的输出流。
每当尝试从任何行缓冲输入流读取时,实现可以(但不是必须)刷新所有行缓冲输出流。
默认情况下不允许实现完全缓冲的流,除非可以确定它们与 "interactive device" 无关。因此,当 stdin/stdout 是终端时,它们不能完全缓冲,只能行缓冲(或无缓冲)。
如果只在输出到终端时才需要刷新,则假设写入换行符会导致刷新就足够了。否则你应该在需要刷新的地方显式调用 fflush
。
参见 the man page for setbuf(3)
。默认情况下,stdout
设置为行缓冲模式。
printf()
及其变体使用缓冲输出,并委托给 write()
。因此,此缓冲由 printf
的 C 库实现控制,缓冲区和缓冲区设置位于 FILE
结构中。
还值得注意的是 unix 手册页第 3 节和第 2 节之间的区别。第 2 部分由直接与操作系统对话的函数调用组成,并执行纯用户程序无法执行的操作。第 3 节由用户可以自己重现的函数调用组成,这些调用通常委托给第 2 节调用。第 2 节函数包含允许 C 程序与外界交互并执行 I/O 的低级 "magic"。第 3 节功能可以为第 2 节功能提供更方便的接口。
printf
、scanf
、getchar
、fputs
和其他 FILE *
函数都是委托给 write()
的第 3 部分函数和 read()
,它们是第 2 部分的函数。 read()
和 write()
不缓冲。 printf()
与 FILE
结构中的缓冲区进行交互,偶尔会决定通过 write()
将该缓冲区的内容发送出去。
有很多情况会自动刷新流上的缓冲输出:
- 当您尝试进行输出并且输出缓冲区已满时。
- 当流关闭时。
- 当程序通过调用 exit 终止时。
- 写入换行符时,如果流是行缓冲的。
- 每当对任何流的输入操作实际从其文件中读取数据时。
stdout
默认为行缓冲。
如果你想在另一个时间刷新缓冲输出,你可以调用 fflush。
自动刷新标准输出缓冲区的规则是实现定义的 (ID)。当流无缓冲、完全缓冲或行缓冲.[=13=时是ID ]
When a stream is unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters may be accumulated and transmitted to or from the host environment as a block.
When a stream is fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled.
When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment.
Support for these characteristics is implementation-defined, ... C11dr §7.21.3 3
I'm just curious which conditions should be satisfied to flush stdout buffer automatically.
如果代码想要确保输出肯定被刷新,请使用 fflush()
。其他可能自动刷新流的条件是实现定义的。
7.21.3 Files
...
3 When a stream is unbuffered, characters are intended to appear from the source or at the
destination as soon as possible. Otherwise characters may be accumulated and
transmitted to or from the host environment as a block. When a stream is fully buffered,
characters are intended to be transmitted to or from the host environment as a block when
a buffer is filled. When a stream is line buffered, characters are intended to be
transmitted to or from the host environment as a block when a new-line character is
encountered. Furthermore, characters are intended to be transmitted as a block to the host
environment when a buffer is filled, when input is requested on an unbuffered stream, or
when input is requested on a line buffered stream that requires the transmission of
characters from the host environment. Support for these characteristics is
implementation-defined, and may be affected via the setbuf
and setvbuf
functions.
...
7 At program startup, three text streams are predefined and need not be opened explicitly
— standard input (for reading conventional input), standard output (for writing
conventional output), and standard error (for writing diagnostic output). As initially
opened, the standard error stream is not fully buffered; the standard input and standard
output streams are fully buffered if and only if the stream can be determined not to refer
to an interactive device.
因此,行缓冲流将在换行时刷新。在我使用过的大多数系统上,stdout
在交互式会话中是行缓冲的。
我只是好奇要满足哪些条件才能自动刷新 stdout 缓冲区。
首先,我很困惑这个伪代码不会在每次迭代时打印输出:
while (1) {
printf("Any text");
sleep(1);
}
但如果我添加换行符,它就会。
经过几次实验,我发现我机器上的标准输出缓冲区被刷新了:
- 当我向标准输出输入 1025 个或更多字符时;
- 当我读取标准输入时;
- 当我将换行符放入标准输出时;
第一个条件完全清楚 - 当缓冲区已满时,应该将其刷新。第二个也是有道理的。但是为什么换行符会导致刷新?其他隐含条件是什么?
每当输出换行符时,应刷新行缓冲的输出流。
每当尝试从任何行缓冲输入流读取时,实现可以(但不是必须)刷新所有行缓冲输出流。
默认情况下不允许实现完全缓冲的流,除非可以确定它们与 "interactive device" 无关。因此,当 stdin/stdout 是终端时,它们不能完全缓冲,只能行缓冲(或无缓冲)。
如果只在输出到终端时才需要刷新,则假设写入换行符会导致刷新就足够了。否则你应该在需要刷新的地方显式调用 fflush
。
参见 the man page for setbuf(3)
。默认情况下,stdout
设置为行缓冲模式。
printf()
及其变体使用缓冲输出,并委托给 write()
。因此,此缓冲由 printf
的 C 库实现控制,缓冲区和缓冲区设置位于 FILE
结构中。
还值得注意的是 unix 手册页第 3 节和第 2 节之间的区别。第 2 部分由直接与操作系统对话的函数调用组成,并执行纯用户程序无法执行的操作。第 3 节由用户可以自己重现的函数调用组成,这些调用通常委托给第 2 节调用。第 2 节函数包含允许 C 程序与外界交互并执行 I/O 的低级 "magic"。第 3 节功能可以为第 2 节功能提供更方便的接口。
printf
、scanf
、getchar
、fputs
和其他 FILE *
函数都是委托给 write()
的第 3 部分函数和 read()
,它们是第 2 部分的函数。 read()
和 write()
不缓冲。 printf()
与 FILE
结构中的缓冲区进行交互,偶尔会决定通过 write()
将该缓冲区的内容发送出去。
有很多情况会自动刷新流上的缓冲输出:
- 当您尝试进行输出并且输出缓冲区已满时。
- 当流关闭时。
- 当程序通过调用 exit 终止时。
- 写入换行符时,如果流是行缓冲的。
- 每当对任何流的输入操作实际从其文件中读取数据时。
stdout
默认为行缓冲。
如果你想在另一个时间刷新缓冲输出,你可以调用 fflush。
自动刷新标准输出缓冲区的规则是实现定义的 (ID)。当流无缓冲、完全缓冲或行缓冲.[=13=时是ID ]
When a stream is unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters may be accumulated and transmitted to or from the host environment as a block.
When a stream is fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled.
When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment.
Support for these characteristics is implementation-defined, ... C11dr §7.21.3 3
I'm just curious which conditions should be satisfied to flush stdout buffer automatically.
如果代码想要确保输出肯定被刷新,请使用 fflush()
。其他可能自动刷新流的条件是实现定义的。
7.21.3 Files
...
3 When a stream is unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters may be accumulated and transmitted to or from the host environment as a block. When a stream is fully buffered, characters are intended to be transmitted to or from the host environment as a block when a buffer is filled. When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment. Support for these characteristics is implementation-defined, and may be affected via thesetbuf
andsetvbuf
functions.
...
7 At program startup, three text streams are predefined and need not be opened explicitly — standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
因此,行缓冲流将在换行时刷新。在我使用过的大多数系统上,stdout
在交互式会话中是行缓冲的。