除非换行符在格式字符串中,为什么printf在调用后不会刷新? 这是POSIX的行为吗? 我怎么可能每次都有printf立即冲洗?
-
你有没有调查过任何文件或只有终端?这听起来是一个聪明的终端功能,不能从后台程序输出未完成的行,但我希望它不适用于前台程序。
-
在Cygwin bash下,即使换行符在格式字符串中,我也会看到同样的错误行为。此问题是Windows 7的新问题;相同的源代码在Windows XP上运行良好。 MS cmd.exe按预期方式刷新。修复setvbuf(stdout, (char*)NULL, _IONBF, 0)解决问题,但肯定不是必需的。我正在使用MSVC ++ 2008 Express。 ~~~
-
为了澄清问题的标题:printf(..)本身不进行任何刷新,它是stdout的缓冲,当看到换行符时(如果它是行缓冲的)可以刷新。它会以相同的方式对putchar('
');作出反应,所以printf(..)在这方面并不特别。这与cout << endl;形成鲜明对比,cout << endl;的文献突出提到了潮红。 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上的缓冲:
-
或者,完全禁用缓冲:setbuf(stdout, NULL);
-
另外,只是想提一下,显然在UNIX中,如果stdout是终端,换行通常只会刷新缓冲区。如果输出被重定向到文件,则换行不会刷新。
-
我觉得我应该补充一下:我刚刚测试了这个理论,我发现在一个没有定向到终端的流上使用setlinebuf()会在每行的末尾进行刷新。
-
@bean当然它确实如此,这就是它的全部要点,并且根据你提供的参数,它不需要setlinebuf的换行符。您可以执行以下操作之一:unbuffered,block buffered和line buffered。无缓冲不需要换行,一旦可用,信息就会出现在目标文件或终端上。
-
"在最初打开时,标准错误流未完全缓冲;标准输入和标准输出流完全缓冲,当且仅当流可以确定不参考交互设备时" - 请参阅此问题:stackoverflow.com /问题/ 5229096 /
-
有没有办法像IDE选项一样持续执行此操作?
-
刚测试,在Mac OS X 10.10.5(优胜美地)setbuf(stdout,NULL);没有达到预期的效果。
-
@RuddZwolinski如果这是一个很好的正典回答"为什么不打印",按照"printf总是在遇到换行时刷新缓冲区?"这一点似乎很重要。直接在这个高度赞成的答案,与需要阅读评论的人...
-
此外,它应该解释为什么流首先被缓冲。知道是否要"解除缓冲"是很重要的。
-
标准说如果输出设备可以被确定为非交互设备,则stdout最初是完全缓冲的。 stackoverflow.com/questions/5229096/
-
值得一提的是,标准库中的exit函数将刷新缓冲区。
-
如果我使用fprintf()打印文件,是否需要fflush(stdout);?
-
"所以只会在到达换行符后显示缓冲区中的内容(或告诉它时)" - >存在其他情况:缓冲区已满。
不,它不是POSIX行为,它是ISO行为(嗯,它是POSIX行为,但只在它们符合ISO的范围内)。
如果可以检测到标准输出是指参考交互式设备,则标准输出是行缓冲的,否则它是完全缓冲的。因此,有些情况下printf将不会刷新,即使它获得了发送的换行符,例如:
这对效率很有意义,因为如果您与用户进行交互,他们可能希望看到每一行。如果您将输出发送到文件,则很可能是另一端没有用户(尽管不是不可能,但他们可能正在拖尾文件)。现在你可以争辩说用户想要看到每个角色但是有两个问题。
首先是它效率不高。第二个原因是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.
-
我刚刚遇到一个场景,即使有' n',printf()也不会刷新。正如你在这里提到的那样,通过添加fflush(stdout)来克服它。但我想知道为什么' n'无法刷新printf()中的缓冲区。
-
@QiangXu,标准输出仅在可以确定为引用交互设备的情况下进行行缓冲。 因此,例如,如果使用myprog >/tmp/tmpfile重定向输出,则完全缓冲而不是行缓冲。 从内存中,确定您的标准输出是否是交互式的是由实现决定的。
-
此外,在Windows上调用setvbuf(....,_ IOLBF)将无法正常工作,因为_IOLBF与_IOFBF相同:msdn.microsoft.com/en-us/library/86cebhfs.aspx
这可能是因为效率,因为如果你有多个程序写入单个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表示刷新所有内容)。
-
请记住fflush(NULL);通常是一个非常糟糕的主意。如果您打开了许多文件,它将会破坏性能,尤其是在多线程环境中,您将与锁定所有内容进行斗争。
注意:Microsoft运行时库不支持行缓冲,因此printf("will print immediatelly to terminal"):
http://msdn.microsoft.com/en-us/library/86cebhfs.aspx
-
更糟糕的是,printf在"正常"情况下立即进入终端的事实是printf和fprintf即使在其输出立即使用的情况下也会得到更粗略的缓冲。除非MS有固定的东西,否则一个程序无法从另一个程序中捕获stderr和stdout,并确定每个程序发送的内容。
默认情况下,stdout是行缓冲的,stderr是无缓冲的,文件是完全缓冲的。
stdout是缓冲的,因此只会在打印换行符后输出。
要获得即时输出,请:
打印到stderr。
使stdout无缓冲。
-
或者fflush(stdout)。
-
"因此只会在打印换行符后输出。"不仅如此,还有至少4个其他案例。缓冲区已满,写入stderr(此答案稍后会提到),fflush(stdout),fflush(NULL)。
你可以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())使内核在内核缓冲区中有数据可用时立即启动写入。