【问题标题】:In C, what's the size of stdout buffer?在 C 中,标准输出缓冲区的大小是多少?
【发布时间】:2026-01-15 04:20:08
【问题描述】:

今天我了解到,stdout 在设置为终端时是行缓冲的,在不同的情况下是缓冲的。因此,在正常情况下,如果我使用 printf() 而不使用终止 '\n' 它将仅在缓冲区已满时打印在屏幕上。如何获取这个缓冲区的大小,这个有多大?

【问题讨论】:

  • 如果您不想要缓冲,为什么不使用不需要它的其他标准库函数之一呢?或者,也许您可​​以只包含 \n 终止符。
  • 我只是不知道标准输出缓冲区的大小。我知道你说的,我只是想知道需要收集多少数据才能认为缓冲区已满并在屏幕上打印文本

标签: c linux unix


【解决方案1】:

实际大小由各个实现定义;该标准没有规定最小尺寸(无论如何,基于我能够找到的内容)。不知道如何确定缓冲区的大小。

编辑

Chapter and verse:

7.19.3 文件

...
3 当流无缓冲时,字符会从源或在 尽快到达目的地。否则可能会累积字符并 作为块传输到主机环境或从主机环境传输。当流完全缓冲时, 字符旨在作为一个块传输到主机环境或从主机环境传输 一个缓冲区被填满。当流被行缓冲时,字符旨在 当换行符被发送到主机环境或从主机环境传输 遭遇。此外,字符旨在作为块传输到主机 填充缓冲区时的环境,在无缓冲流上请求输入时,或 当在需要传输的行缓冲流上请求输入时 来自宿主环境的字符。 对这些特性的支持是 实现定义,可能会受到setbufsetvbuf 函数的影响

添加了重点。

“实现定义”不是“我不知道”的委婉说法,它只是语言标准明确将其留给实现定义的声明em>行为。

话虽如此, 有一种非编程方式可以找出答案;请查阅编译器的文档。 “实现定义”还意味着实现必须记录行为:

3.4.1

1 实现定义的行为
未指定的行为,其中每个实现都记录了如何做出选择

2 示例 实现定义行为的一个示例是高阶位的传播 当有符号整数右移时。

【讨论】:

  • 我经常听到'这取决于实施',以至于我开始认为有时这只是说'我不知道'的方式,但你已经说清楚了,好吧; p
  • “它取决于实现”意味着实现者可以按照他们认为合适的方式实现它并且仍然符合标准。如果你真的想知道那个缓冲区有多大,你可以继续写入它而不用任何“\n”直到它溢出。
  • 如何查看缓冲区是否溢出,最后没有字符打印,又从1开始?
  • 您可以将字符的计数打印到 stderr(未缓冲)并查看第一个缓冲字符何时出现,我将实现作为作业留给您。
  • 这实际上取决于您使用的 libc,而不是编译器。
【解决方案2】:

使用默认管道大小 64K 创建管道时的 Linux。 在 /proc/sys/fs/pipe-max-size 中存在最大管道大小。 因为默认 1048576 是典型的。

用于glibc的默认文件缓冲区; 65536 字节似乎是合理的。 但是,由 glibc 源代码树中的 grep 确定: libio/libio.h:#define _IO_BUFSIZ _G_BUFSIZ sysdeps/generic/_G_config.h:#define _G_BUFSIZ 8192 sysdeps/unix/sysv/linux/_G_config.h:#define _G_BUFSIZ 8192

原来的问题可能会或可能不会被回答。 一分钟的努力,最好的猜测是 8 KB。

对于单纯的行缓冲,8K 就足够了。 但是,对于超过行缓冲的输出 与 64K 相比; 8K 效率不高。 因为对于默认管道大小,使用 64K 并且 如果不希望有更大的管道尺寸并且 如果未明确设置较大的管道​​尺寸 那么对于 stdio 缓冲区,建议使用 64K。

如果需要性能 那么微薄的 8K 缓冲区是不够的。 通过 fcntl(pipefd,F_SETPIPE_SZ,1048576) 可以增加管道的尺寸。 通过 setvbuf (stdout,buffer,_IOFBF,1048576) 可以替换 stdio 提供的文件缓冲区。 如果不使用管道 那么管道尺寸无关紧要。 但是,如果在两个进程之间通过管道传输数据 然后通过增加管道尺寸可以提高性能。 否则 通过最小的缓冲区或 通过最小的管道 产生了瓶颈。

如果还阅读 然后通过更大的缓冲区 通过 stdio,可能需要更少的读取函数调用。 “可能”这个词暗示了一个重要的考虑因素。 如提供 通过单个写入函数调用 通过单个读取函数调用 可以读取尽可能多的数据。 通过读取函数调用 可以预期返回的字节数少于请求的字节数。 通过额外的读取函数调用 可能会获得额外的字节。

用于写数据线;通过 stdio overkill 提供。 但是,通过 stdio 行缓冲输出是可能的。 在某些情况下,行缓冲输出是必不可少的。 如果写入 proc 虚拟文件系统提供的文件或 如果写入 sys 虚拟文件系统提供的文件 然后在单个写缓冲区中 应该包括换行字节。 如果使用第二次写入 那么可能会出现意想不到的结果。

如果读写和stdio混合使用 然后存在警告。 前 写函数调用 需要 fflush 函数调用。 因为 stderr 没有被缓冲; 对于 stderr,不需要 fflush 函数调用。 通过读取可能会提供少于预期的字节数。 通过 stdio,之前的字节可能已经被缓冲了。

不混合 unistd 和 stdio I/O 是个好建议,但经常被忽略。 混合缓冲输入是不合理的。 混合无缓冲输入是可能的。 混合缓冲输出是合理的。

通过 stdio 缓冲 IO 提供了便利。 没有 stdio 缓冲 IO 是可能的。 但是,对于代码,需要额外的字节。 当利用足够大的缓冲区时; 与 stdio 提供的输出功能相比; 写函数调用不一定慢。

但是,当不涉及管道时 然后通过函数 mmap 可以提供优越的 IO。 在 mmap 的管道上,不会返回错误。 但是,在地址空间中不提供数据。 lseek 在管道上提供了一个错误。

最后由 man 3 setvbuf 提供了一个很好的例子。 如果在堆栈上分配缓冲区 然后在返回 fclose 函数调用之前 不能省略。

实际的问题是 “在 C 中,标准输出缓冲区的大小是多少?” 到 8192 时,可能会回答很多问题。

由遇到此询问的人 可能存在关于缓冲区输入/输出效率的好奇心。 通过一些调查,目标是隐含的。 偏好简洁的回复 管道尺寸的意义和 缓冲区大小的意义和 mmap 没有说明。 这个回复说明了。

【讨论】:

    【解决方案3】:

    here 是关于类似问题的一些非常有趣的答案。

    在 linux 系统上,您可以查看不同函数的缓冲区大小,包括 ulimit。 头文件limits.hpipe.h 也应该包含这种信息。

    【讨论】:

      【解决方案4】:

      您可以将其设置为无缓冲,或者只是刷新它。

      当 C 运行时通常为您刷新它和一些示例时,这似乎有一些不错的信息。看看this

      【讨论】:

      • Thx,但我想知道必须收集多少数据才能使缓冲区被视为已满以及在 Linux 或其他 *nik 系统中打印在屏幕上的文本?经常提到的虚构 BUFFER 的大小是多少。