关于C#:为什么printf在调用后不会刷新,除非换行符在格式字符串中?

Why does printf not flush after the call unless a newline is in the format string?

除非换行符在格式字符串中,为什么printf在调用后不会刷新? 这是POSIX的行为吗? 我怎么可能每次都有printf立即冲洗?


默认情况下,stdout流是行缓冲的,因此只有在到达换行符后(或者告诉它时)才会显示缓冲区中的内容。您可以选择立即打印:

使用fprintf打印到stderr(默认情况下stderr未缓冲):

1
fprintf(stderr,"I will be printed immediately");

无论何时需要使用fflush刷新标准输出:

1
2
printf("Buffered, will be flushed");
fflush(stdout); // Will now print everything in the stdout buffer

编辑:从下面的Andy Ross的评论中,您还可以使用setbuf禁用stdout上的缓冲:

1
setbuf(stdout, NULL);


不,它不是POSIX行为,它是ISO行为(嗯,它是POSIX行为,但只在它们符合ISO的范围内)。

如果可以检测到标准输出是指参考交互式设备,则标准输出是行缓冲的,否则它是完全缓冲的。因此,有些情况下printf将不会刷新,即使它获得了发送的换行符,例如:

1
myprog >myfile.txt

这对效率很有意义,因为如果您与用户进行交互,他们可能希望看到每一行。如果您将输出发送到文件,则很可能是另一端没有用户(尽管不是不可能,但他们可能正在拖尾文件)。现在你可以争辩说用户想要看到每个角色但是有两个问题。

首先是它效率不高。第二个原因是ANSI C的原始授权主要是对现有行为进行编码,而不是发明新行为,而这些设计决策是在ANSI开始流程之前做出的。在改变标准中的现有规则时,即便是ISO现在也非常谨慎。

至于如何处理,如果你想在每次输出调用后fflush (stdout),那将解决问题。

或者,您可以在stdout上操作之前使用setvbuf,将其设置为无缓冲,您不必担心将所有fflush行添加到代码中:

1
setvbuf (stdout, NULL, _IONBF, BUFSIZ);

请记住,如果要将输出发送到文件,可能会影响性能。另请注意,对此的支持是实现定义的,不受标准保证。

ISO C99部分7.19.3/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.


这可能是因为效率,因为如果你有多个程序写入单个TTY,这样你就不会在一行上交换字符。因此,如果程序A和B正在输出,您通常会得到:

1
2
3
4
5
program A output
program B output
program B output
program A output
program B output

这很糟糕,但它比

1
2
3
proprogrgraam m AB  ououtputputt
prproogrgram amB A  ououtputtput
program B output

请注意,它甚至不能保证在换行符上刷新,因此如果刷新对您很重要,则应明确刷新。


要立即刷新call fflush(stdout)fflush(NULL)(NULL表示刷新所有内容)。


注意:Microsoft运行时库不支持行缓冲,因此printf("will print immediatelly to terminal")

http://msdn.microsoft.com/en-us/library/86cebhfs.aspx


默认情况下,stdout是行缓冲的,stderr是无缓冲的,文件是完全缓冲的。


stdout是缓冲的,因此只会在打印换行符后输出。

要获得即时输出,请:

  • 打印到stderr。
  • 使stdout无缓冲。

  • 你可以fprintf到stderr,它是无缓冲的。或者你可以在你想要的时候刷新标准输出。或者您可以将stdout设置为unbuffered。


    使用setbuf(stdout, NULL);禁用缓冲。


    一般有2个级别的缓冲 -

    1.内核缓冲区缓存(使读/写更快)

    2.在I / O库中缓冲(减少系统调用次数)

    我们以fprintf and write()为例。

    当您调用fprintf()时,它不会直接转到该文件。它首先进入程序内存中的stdio缓冲区。从那里通过使用write系统调用将其写入内核缓冲区高速缓存。因此,跳过I / O缓冲区的一种方法是直接使用write()。其他方法是使用setbuff(stream,NULL)。这将缓冲模式设置为无缓冲,并将数据直接写入内核缓冲区。
    为了强制使数据转移到内核缓冲区,我们可以使用" n",在"行缓冲"的默认缓冲模式的情况下,将刷新I / O缓冲区。
    或者我们可以使用fflush(FILE *stream)

    现在我们在内核缓冲区。内核(/ OS)希望最小化磁盘访问时间,因此它只读取/写入磁盘块。因此,当发出read()(系统调用并且可以直接或通过fscanf()调用)时,内核会从磁盘读取磁盘块并将其存储在缓冲区中。之后,数据从此处复制到用户空间。

    类似地,从I / O缓冲区收到的fprintf()数据由内核写入磁盘。这使得read()write()更快。

    现在强制内核启动write(),之后数据传输由硬件控制器控制,也有一些方法。我们可以在写调用期间使用O_SYNC或类似的标志。或者我们可以使用其他函数(如fsync(),fdatasync(),sync())使内核在内核缓冲区中有数据可用时立即启动写入。