bub*_*ble 18 c io stdio console-application c-standard-library
这些getch
和getchar
功能之间的确切区别是什么?
Roy*_*tus 28
getchar()
是一个从stdin获取字符的标准函数.
getch()
是非标准的.它从键盘获取一个字符(可能与stdin不同)并且不回显它.
标准 C 函数是getchar()
,在 中声明<stdio.h>
。它基本上从一开始就存在。它从标准输入 ( stdin
)读取一个字符,这通常是用户的键盘,除非它已被重定向(例如通过 shell 输入重定向字符<
或管道)。
getch()
和getche()
是旧的 MS-DOS 函数,在 中声明<conio.h>
,并且仍然在 Windows 系统上流行。它们不是标准的 C 函数;它们并非存在于所有系统上。getch
立即从键盘读取一个击键,无需等待用户按下 Return 键,也不会响应击键。getche
是一样的,除了它会回声。据我所知,getch
并且getche
总是从键盘读取; 它们不受输入重定向的影响。
问题自然就来了,如果getchar
是标准函数,怎么用它来读取一个字符而不等待回车键,或者不回显?这些问题的答案至少有点复杂。(事实上,它们足够复杂,我怀疑它们解释了getch
and的持久流行getche
,如果没有别的,它们很容易使用。)
答案是它getchar
无法控制回显和输入缓冲等细节——就 C 而言,这些是较低级别的、依赖于系统的问题。
但是理解getchar
假设的基本输入模型是有用的。令人困惑的是,通常有两种不同的缓冲级别。
当用户在键盘上键入键时,操作系统的终端驱动程序会读取这些键。通常,在其默认模式下,终端驱动程序在键入时立即回显击键(因此用户可以看到他们正在键入的内容)。通常,在其默认模式下,终端驱动程序还支持一定数量的行编辑——例如,用户可以按 Delete 或 Backspace 键来删除意外键入的字符。为了支持行编辑,终端驱动程序通常在输入缓冲区中收集字符. 只有当用户点击 Return 时,该缓冲区的内容才可供调用程序使用。(仅当标准输入实际上是键盘或其他串行设备时才存在此级别的缓冲。如果标准输入已重定向到文件或管道,则终端驱动程序无效并且此级别的缓冲不适用。)
stdio 包从操作系统读取字符到它自己的输入缓冲区。 getchar
只需从该缓冲区中获取下一个字符。当缓冲区为空时,stdio 包尝试通过从操作系统读取更多字符来重新填充它。
因此,如果我们跟踪程序getchar
第一次调用时开始发生的事情:stdio 发现其输入缓冲区为空,因此它尝试从操作系统读取一些字符,但还没有任何字符可用,因此read
调用块。同时,用户可能正在键入一些字符,这些字符在终端驱动程序的输入缓冲区中累积,但用户还没有按回车键。最后,用户点击 Return,被阻塞的read
调用返回,将整行的字符返回给stdio
,它使用它们来填充其输入缓冲区,然后将第一个字符返回到初始调用getchar
,一直耐心等待一直在等待。(然后如果程序getchar
第二次或第三次调用,可能有还有一些字符——用户键入的行上的下一个字符——在 stdio 的输入缓冲区中可用getchar
以立即返回。有关更多信息,请参阅这些C 课程笔记的第 6.2 节。)
但在所有这些中,正如您所看到的,getchar
stdio 包无法控制诸如回显或输入行编辑之类的细节,因为这些细节在步骤 1 中的终端驱动程序中更早地在较低级别处理。
因此,至少在类 Unix 操作系统下,如果您想在不等待 Return 键的情况下读取字符,或者控制是否回显字符,您可以通过调整终端驱动程序的行为来实现。细节各不相同,但有一种方法可以打开和关闭回声,还有一种方法(实际上有几种方法)可以打开和关闭输入行编辑。(至少要了解其中的一些细节,请参阅此 SO 问题或旧C 常见问题列表中的问题 19.1。)
当输入行编辑关闭时,操作系统可以立即返回字符(无需等待回车键),因为在这种情况下,它不必担心用户可能输入了错误的需要“采取”的击键后退”用 Delete 或 Backspace 键。(但同理,当一个程序在终端驱动中关闭输入行编辑时,如果想让用户更正错误,就必须实现自己的编辑,因为它会看到---即连续调用getchar
将返回——用户的错误字符和Delete 或 Backspace 键的字符代码。)