为什么printf在调用后不刷新,除非格式字符串中有换行符?这是POSIX行为吗?如何让printf每次都立即刷新?


当前回答

立即刷新调用fflush(stdout)或fflush(NULL) (NULL表示刷新所有内容)。

其他回答

不,它不是POSIX行为,它是ISO行为(好吧,它是POSIX行为,但只是在它们符合ISO的情况下)。

标准输出是行缓冲的,如果它可以检测到指向交互设备,否则它是完全缓冲的。所以有些情况下,printf不会刷新,即使它得到一个换行符发送出去,例如:

myprog >myfile.txt

这对于效率是有意义的,因为如果你与用户交互,他们可能想看到每一行。如果您将输出发送到一个文件,很可能另一端没有用户(尽管也不是不可能,他们可能在跟踪文件)。现在你可能会说用户想要看到每个字符,但这有两个问题。

首先是效率不高。其次,最初的ANSI C要求主要是编纂现有的行为,而不是发明新的行为,而且这些设计决策早在ANSI开始这个过程之前就已经做出了。现在,即使是ISO在改变标准中的现有规则时也非常谨慎。

至于如何处理这个问题,如果在您希望立即看到的每个输出调用之后进行fflush (stdout),就可以解决问题。

或者,你可以在操作stdout之前使用setvbuf,将其设置为unbuffered,这样你就不必担心在代码中添加所有的fflush行:

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.

注意:Microsoft运行时库不支持行缓冲,因此printf(“将立即打印到终端”):

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setvbuf

stdout流在默认情况下是行缓冲的,因此只会在它到达换行符后(或当它被告知时)显示缓冲区中的内容。你有几个选项可以立即打印:

使用fprintf打印到stderrinstead (stderr默认是无缓冲的): fprintf(stderr,“我将立即被打印”); 在需要时使用fflush刷新标准输出: printf("Buffered, will flush "); 。fflush (stdout);//现在打印stdout缓冲区中的所有内容 使用setbuf禁用stdout的缓冲: setbuf (stdout, NULL); 或者使用更灵活的setvbuf: setvbuf(stdout, NULL, _IONBF, 0);

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

立即刷新调用fflush(stdout)或fflush(NULL) (NULL表示刷新所有内容)。