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


当前回答

你可以fprintf到stderr,这是无缓冲的。或者您可以在需要时刷新stdout。或者你可以将stdout设置为unbuffered。

其他回答

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);

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

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

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

这样做可能是为了提高效率,也因为如果有多个程序写入一个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

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

一般有2级缓冲-

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

2. I/O库中的缓冲(减少no。系统调用)

让我们以fprintf和write()为例。

When you call fprintf(), it doesn't wirte directly to the file. It first goes to stdio buffer in the program's memory. From there it is written to the kernel buffer cache by using write system call. So one way to skip I/O buffer is directly using write(). Other ways are by using setbuff(stream,NULL). This sets the buffering mode to no buffering and data is directly written to kernel buffer. To forcefully make the data to be shifted to kernel buffer, we can use "\n", which in case of default buffering mode of 'line buffering', will flush I/O buffer. Or we can use fflush(FILE *stream).

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

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

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