8.2 缓冲区

当您在一些系统上运行前面的程序时,您所输入的文本立即回显。也就是说,一个可能的运行示例如下所示:

阅读 ‧ 电子书库

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

前面描述的行为是例外的情况。在大多数系统上,在您按下回车键之前什么都不会发生,正如在第一个例子中所示。输入字符的立即回显是非缓冲(unbuffered)或直接(direct)输入的一个实例,它表示您所键入的字符对正在等待的程序立即变为可用。相反,延迟回显是缓冲(buffered)输入的实例,这种情况下您所键入的字符被收集并存储在一个被称为缓冲区(buffer)的临时存储区域中。按下回车键可使您所键入的字符块对程序变为可用。图8.1对这两种类型的输入进行了比较。

阅读 ‧ 电子书库

图8.1 缓冲输入与非缓冲输入

为什么需要缓冲区?首先,将若干个字符作为一个块传输比逐个发送这些字符耗费的时间少。其次,如果您输入有误,就可以使用您的键盘更正功能来修正错误。当最终按下回车键时,您就可以发送正确的输入。

另一方面,一些交互性的程序需要非缓冲输入。例如,在游戏中,您希望一按下键就执行某个命令。因此,缓冲和非缓冲输入具有它们各自的用途。

缓冲分为两类:完全缓冲(fully buffered)I/O和行缓冲(line-buffered)I/O。对完全缓冲输入来说,缓冲区满时被清空(内容被发送至其目的地)。这种类型的缓冲通常出现在文件输入中。缓冲区的大小取决于系统,但512字节和4096字节是常见的值。对行缓冲I/O来说,遇到一个换行字符时将被清空缓冲区。键盘输入是标准的行缓冲,因此按下回车键将清空缓冲区。

您具有哪种类型的输入:缓冲还是非缓冲?ANSI C指定应该对输入进行缓冲,而K&R则将选择权留给了编译器的编写者。您可以通过运行echo.c程序并观察出现的行为来查明您的输入类型。

ANSI C决定将缓冲输入作为标准的原因是一些计算机设计不允许非缓冲输入。如果您的特定计算机确实允许非缓冲输入,则很可能您的C编译器会提供非缓冲输入作为选项。例如,许多IBM PC兼容机的编译器通常会提供一个专门用于非缓冲输入的函数系列。这些函数由conio.h头文件支持,其中包括用于回显的非缓冲输入的getche()和用于不回显的非缓冲输入的getche()(回显的输入意味着您键入的字符会在屏幕上显示,不回显的输入则意味着不显示您的击键)。Unix系统使用一种不同的方法,因为Unix自己控制缓冲。在Unix下,可使用ioctl()函数(Unix库的一部分,但不是标准C的一部分)来指定您所需要的输入类型,getchar()将按照该类型运行。在ANSI C中,setbuf()和setvbuf()函数(第13章“文件输入/输出”)提供了对缓冲的一些控制,但一些系统的内在限制会约束这些函数的效用。简言之,不存在调用非缓冲输入的标准ANSI方式;使用的方法取决于计算机系统。在本书中,怀着对使用非缓冲输入的朋友的歉意,我们假设您在使用缓冲输入。