C语言中的缓冲输入和非缓冲输入

20

除了手册之外,有没有其他方法可以确定输入是缓冲还是非缓冲的?我们能否通过观察函数名称来确定? 同样适用于回显不回显的情况... 在哪里可以快速查找包含缓冲非缓冲回显不回显输入详细信息的列表?


1
抱歉,你说“除了man页面”。评论已删除。顺便提一下,setbuf可能会有帮助。 - user2363448
我认为没有一种可移植的方法可以检测特定的打开文件流(FILE *)是缓冲还是非缓冲。无论如何,你为什么需要知道呢? - Jonathan Leffler
我不想在运行时知道它。但是有没有办法知道哪个函数是缓冲的或非缓冲的,回显的或非回显的...通过查看函数名称,是否可能?否则,任何关于哪个函数是缓冲的和哪个函数不是的链接都会有所帮助。 - StackIT
3个回答

33
所有用于从FILE读取的stdio.h函数都可能具有“缓冲”或“非缓冲”行为,以及“回显”或“非回显”行为。控制这些行为的因素不是您使用的函数,而是流和/或其底层文件描述符上的设置。请保留HTML标签。
  • 标准库函数setvbuf可用于启用或禁用C库对输入(和输出)的缓冲。这对操作系统的缓冲没有影响。有三种可能的模式:“完全缓冲”(以实质性块方式读取或写入);“行缓冲”(缓冲直到读取或写入'\n'字符,但不超过该字符);和“无缓冲”(所有读取和写入立即传输到操作系统)。

  • FILE对象(包括stdin和friends)的默认缓冲是实现定义的。Unix C库通常将所有FILE默认设置为完全缓冲,但有两个例外。 stderr默认为无缓冲。对于任何其他FILE,如果在第一次实际读取或写入时未使用setvbuf,并且isatty对于底层文件描述符为真,则FILE变为行缓冲。

  • 一些C库提供扩展函数,例如Linux和Solaris上的__flbf和friends,用于读取由setvbuf控制的某些设置。请记住,如上所述,如果未明确设置,缓冲模式可以在第一次实际读取或写入时更改。

如果输入来自文件,则setvbuf是您唯一拥有的调整手柄。如果输入来自某种通信渠道,则可能有其他手柄:
在符合POSIX标准的系统上(即“除了Windows之外的所有系统”),程序可以请求终端输入的多种模式。其中,最重要的区别是“规范模式”和“非规范模式”。处于规范模式的终端同时具有缓冲和回显功能。(此缓冲与如果未使用setvbuf禁用缓冲的C库所进行的缓冲是分开的。)非规范模式允许您单独切换缓冲和回显。低级POSIX终端接口非常广泛、复杂,并允许您读取和写入所有这些设置。
如果您认为需要将终端置于非规范模式,请在针对低级POSIX API编写大量代码之前,首先考虑readlinencurses库是否能够使您的生活更轻松。
如果您从管道中读取数据,则受到编写该管道数据的人的控制;您无法控制获取的块的大小。
如果您从套接字中读取数据,则通过仔细使用recvmsg可能能够对获取的块的大小进行一定程度的控制,但并不保证。
我不知道Windows上的情况。

看完你的帖子后,我删掉了我的。谢谢你的回答。+1 - user1814023
我有几个问题要问你。 是谁为标准库函数设置setvbuf?(标准库函数默认是行缓冲的吗?) 我们可以使用哪个函数来设置回显和非回显功能? 一些关于使用setvbuf控制缓冲区的示例会很有帮助。谢谢。 - user1814023
1
@NishithJainMR 我已经在答案的文字中添加了关于默认stdio缓冲行为的说明。我不想提供更多有关回显的信息,因为我不想给人留下关闭回显很简单的印象。实际的系统调用很简单,但是他们会导致一系列令人惊讶的后果。几乎所有情况下,应该使用ncursesreadline代替;它们提供了更高级别的API,平滑处理了所有这些后果。 - zwol
1
在Windows上(至少是mingw),所有文件都是完全缓冲的,包括stdout甚至是stderr;可以使用setbuf()setvbuf() - loreb

4

ISO/IEC 9899-1999 C99语言标准

5.1.2.3 程序执行

...

5) 交互设备的输入和输出动态应按照7.19.3中指定的方式进行。这些要求的目的是为了确保未经缓冲或行缓冲的输出尽快出现,以确保在程序等待输入之前实际显示提示消息。 ...

7.19.3 文件

...

3) 当流是未经缓冲的时,字符应尽快从源或目的地中显示。否则,字符可能会被累积并作为块传输到或从主机环境中。当流是完全缓冲时,当缓冲区被填满时,字符被意图作为块传输到或从主机环境中。当流是行缓冲时,当遇到新行字符时,字符被意图作为块传输到或从主机环境中。此外,在未经缓冲的流上请求输入,或者在需要从主机环境传输字符的行缓冲流上请求输入时,字符被意图作为块传输到主机环境中。对于这些特性的支持是实现定义的,并且可以通过setbuf和setvbuf函数进行影响。 ...

7) 在程序启动时,三个文本流被预定义并且不需要显式打开——标准输入(用于读取传统输入)、标准输出(用于写入传统输出)和标准错误(用于写入诊断输出)。在最初打开时,标准错误流未完全缓冲;当且仅当可以确定流不是交互设备时,标准输入和标准输出流才是完全缓冲的。


2

您可以使用 setvbuf() 将缓冲区与文件(包括 stdin)关联。您可以将缓冲模式更改为完全、行或无缓冲。


3
没错,但这并不能帮助检测特定的开放流是缓冲还是非缓冲,而这才是我认为问题所询问的。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接