printf 缓冲是 C 标准的一部分吗?

Posted

技术标签:

【中文标题】printf 缓冲是 C 标准的一部分吗?【英文标题】:Is printf buffering part of the C standard? 【发布时间】:2021-12-11 21:54:54 【问题描述】:

我正在 Linux 上用 C 语言编写一个程序,其中各种内容将通过printf 写入stdout。自然,我会尽量减少 IO 调用并缓冲所有信息,然后将其传递给单个打印调用。但是,通过测试,我发现printf 会自行缓冲,直到达到'\n'。 我的问题是,我可以确定所有 printf 实现都这样做,还是 glibc 刚刚优化?信任printf为我做缓冲可靠吗?

【问题讨论】:

@EugeneSh。谢谢。 虽然不具有权威性,但措辞on cppreference 有点暗示它部分是。 stdinstdout 必须完全缓冲,除非连接到交互式设备。 stderr 永远不会完全缓冲。 @Someprogrammerdude 实际上它由标准规定的,所以我收回我的第一条评论:port70.net/~nsz/c/c11/n1570.html#7.21.3p7 我会说假设printf 被缓冲是安全的。我想说,任何将字符捆绑在自己的显式缓冲区中的尝试,以人为地最小化实际printf 调用的数量,这将是一种巨大且不必要的时间浪费。 (对于没有实际缓冲的嵌入式平台,可能有带有微型 C 库的编译器。你是在为这样的环境编程吗?你说的是 Linux,所以我猜不是。) @SteveSummit 有无缓冲的微控制器实现。但是在这种适用的低端系统上,无论如何使用stdio.h 被认为是非常糟糕的做法,因为像 printf 这样的函数会扼杀所有可用的内存和执行速度。 【参考方案1】:

C 标准允许无缓冲和缓冲流。相关部分是C17 7.21.3/3:

当流无缓冲时,字符会尽快从源或目标出现。否则,字符可能会作为一个块累积并传输到主机环境或从主机环境传输。当一个流完全缓冲时,当缓冲区被填满时,字符将作为一个块传输到主机环境或从主机环境传输。当流被行缓冲时,当遇到换行符时,字符将作为块传输到主机环境或从主机环境传输。

这通常取决于操作系统而不是标准库实现。大多数托管的基于控制台的操作系统使用行缓冲实现,\n 将“刷新缓冲区”。否则,对fflush(stdout) 的显式调用将始终执行此操作(严格来说它更便携)。

无缓冲系统的一个例子是有限的“裸机”微控制器,其中stdout 是一个 UART,没有硬件缓冲区来存储大量字符。

【讨论】:

我还要补充一点,默认情况下输出流是否完全缓冲取决于设备是否“交互式”,其定义是实现定义的。 @sj95126 “交互式”是一些 C 标准的无意义术语。我提到的那种无缓冲微控制器系统可以与 PC 端的终端进行大量交互。事实是,写这篇文章的人,可能一直追溯到丹尼斯里奇,几乎只考虑 Unix。 也许它已经过时了,但在 C2x 草案中,措辞仍然在标准中。我只是指出它就在那里,仅此而已。 @sj95126 是的,同一部分中的流章节是“输入和输出,无论是来自终端和磁带驱动器等物理设备还是来自物理设备”。我个人只在技术博物馆看到过磁带驱动器。除非它可能指的是好的老式点阵打印机,否则它们在 90 年代仍在使用......

以上是关于printf 缓冲是 C 标准的一部分吗?的主要内容,如果未能解决你的问题,请参考以下文章

fprintf和printf有啥区别吗?

Go语言标准库之fmt

go语言标准库之fmt

printf 和 fprintf 在c 和c++中的使用。

printf函数用于啥?

运行时库只是一些动态链接的库文件吗? [关闭]