为什么printf在调用之后不刷新,除非换行符在格式化string中?
为什么printf
在调用之后不刷新,除非换行符在格式化string中? 这是POSIX的行为? 我怎样才能让printf
每次立即刷新?
stdout
stream被缓冲,所以只会在到达换行符(或者被告知)时显示缓冲区中的内容。 你有几个select立即打印:
使用fprintf
打印到stderr:
fprintf(stderr, "I will be printed immediately");
在需要使用fflush
时刷新stdout:
printf("Buffered, will be flushed"); fflush(stdout); // Will now print everything in the stdout buffer
编辑 :从下面的Andy Ross的评论,你也可以使用setbuf
禁用标准输出缓冲:
setbuf(stdout, NULL);
不,这不是POSIX行为,而是ISO行为(嗯,这是 POSIX的行为,但只要符合ISO标准)。
如果可以检测到标准输出是指交互式设备,则标准输出是行缓冲的,否则它是完全缓冲的。 所以有些情况下printf
不会被刷新,即使它得到一个换行符,例如:
myprog >myfile.txt
这对于效率是有意义的,因为如果你与用户交互,他们可能希望看到每一行。 如果你将输出发送到一个文件,很可能是另一端没有用户(尽pipe不是不可能的,他们可能是拖曳文件)。 现在你可以争辩说,用户想看到每一个angular色,但有两个问题。
首先是效率不高。 第二个原因是ANSI C的主要任务是对现有的行为进行编纂,而不是发明新的行为,而这些devise决定是在ANSI开始这个过程之前就做出的。 即使ISO现在在改变标准中的现有规则时也非常谨慎。
至于如何处理这个问题,如果你立即看到每个输出调用之后fflush (stdout)
如果你fflush (stdout)
,那么这个问题就解决了。
或者,您可以在stdout
上使用setvbuf
之前,将其设置为无缓冲,您将不必担心将所有这些fflush
行添加到您的代码:
setvbuf (stdout, NULL, _IONBF, BUFSIZ);
请记住,如果要将输出发送到文件,可能会影响性能。 同时请记住,对此的支持是由实现定义的,而不是由标准保证的。
ISO C99第7.19.3/3
节是相关位:
当一个数据stream没有缓冲的时候 ,字符应该尽可能的从源头或目的地出现。 否则,字符可以积累并作为一个块被传送到主机环境或从主机环境传送。
当一个stream被完全缓冲时 ,当缓冲区被填满时,字符被打算作为一个块被传输到主机环境或从主机环境传输。
当一个stream是行缓冲的时候 ,当遇到一个换行符时 ,字符被打算作为一个块被传送到主机环境或从主机环境传送出去。
此外,当填充缓冲区,当在非缓冲stream上请求input时,或者在需要从主机环境传输字符的线路缓冲stream上请求input时,字符意图作为块被传输到主机环境。
对这些特征的支持是由实现定义的,并可能通过
setbuf
和setvbuf
函数来影响。
这可能是因为效率,如果你有多个程序写入一个单一的TTY,这样你就不会在一行中交错字符。 所以如果程序A和B正在输出,你通常会得到:
program A output program B output program B output program A output program B output
这很臭,但比它好
proprogrgraam m AB ououtputputt prproogrgram amB A ououtputtput program B output
请注意,甚至不保证在换行符上刷新,所以如果刷新对你来说很重要,你应该明确地刷新。
立即刷新调用fflush(stdout)
或fflush(NULL)
( NULL
表示刷新所有内容)。
stdout被缓冲,因此只有在打印换行符后才会输出。
要获得即时输出,可以:
- 打印到stderr。
- 使标准输出无缓冲。
注意:Microsoft运行时库不支持行缓冲,因此printf("will print immediatelly to terminal")
:
默认情况下,stdout是行缓冲的,stderr没有被缓冲,文件被完全缓冲。
您可以将fprintf改为stderr,而不是缓冲区。 或者你可以刷新标准输出,当你想要的。 或者你可以设置标准输出为无缓冲。
使用setbuf(stdout, NULL);
禁用缓冲。