何时可以期望将“stdout”打印到控制台?

3

我知道这是由于stdout的缓冲,但是在以下程序中,我什么时候可以期望stdout的输出。如果我运行,我总是得到"stderr"作为输出。只有当我添加'\n'或fflush(stdout)时,我才会得到两个语句。如果我不添加'\n'或fflush(stdout),我就不会得到"stdout"作为输出。如果我不添加'\n'或fflush(stdout),什么时候才能得到所有缓冲的"stdout"作为输出。

#include <stdio.h>
#include <unistd.h>
int main()
{
      for(;;)
      {
              fprintf(stdout,"stdout");
              fprintf(stderr,"stderr");
              sleep(1);
      }
      return 0;
} 
3个回答

4

事实上,默认情况下,如果 stdout 引用终端设备,则会进行行缓冲或清空。

更准确地说:只有当标准输入和标准输出不引用交互式设备时,它们才是完全缓冲的。标准错误永远不会被完全缓冲。

关于行缓冲,引用自 APUE

行缓冲带有两个注意点。首先,标准 I/O 库用于收集每行的缓冲区的大小是固定的,因此如果在写入换行符之前填满了该缓冲区,则可能进行 I/O 操作。其次,每当从未缓冲的流或需要从内核请求数据的行缓冲流(例如,要求数据通过标准 I/O 库从内核请求)请求输入时,所有行缓冲输出流都会被刷新。对于(b)上的限定语的原因是,请求的数据可能已经存在于缓冲区中,这不需要从内核读取数据。显然,来自未缓冲的流(项 a)的任何输入都需要从内核获取数据。

要将其更改为无缓冲,请使用setvbuf

setvbuf(stdout, NULL, _IONBF, 0);

我的问题是,如果我不添加 '\n' 或 fflush(stdout),那么所有缓冲的 stdout 什么时候会打印到控制台? - Chinna
1
@Chinna 当 stdout FILE* 的内部缓冲区已满时,会发生这种情况。该缓冲区的大小取决于平台,但通常为1024或4096字节。 - nos

0

通常情况下,发送到 stderr 的输出会立即打印。它是标准错误输出。当然,错误应该立即显示,因此存在的任何缓冲区都会立即刷新。

另一方面,stdout 是带缓冲区的。将该缓冲区打印出来的方式因语言而异,但通常需要以下两个选项中的至少一个: /n 或其他类型的换行符,或者 .flush(); 如果您没有提供这些选项,那么通常必须等待缓冲区填充。这可能需要任意数量的时间,因为它基本上完全取决于缓冲区的大小。

根据惯例,处理流的方式是将尽可能多的信息推入其中,然后调用 .flush()。如果在此期间缓冲区恰好填满,则数据将被发送到其目的地,并且缓冲区重新开始填充。

在这里,您正在填充接收文本的缓冲区。与二进制信息相比,文本实际上不需要太多的空间(这是一个非常主观的说法,应该松散解释),因此填充缓冲区可能需要相当长的时间。

最佳实践是在您“喂”完要打印的所有文本后手动刷新流(stdout)。


0

fprintf 默认情况下是行缓冲的。您可以通过调用 setvbuf 来更改其行为。它允许您将其设置为“无缓冲”,“行缓冲”或“完全缓冲”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接