getch()和getchar()有什么区别?

bub*_*ble 18 c io stdio console-application c-standard-library

这些getchgetchar功能之间的确切区别是什么?

Roy*_*tus 28

getchar() 是一个从stdin获取字符的标准函数.

getch()是非标准的.它从键盘获取一个字符(可能与stdin不同)并且不回显它.

  • 这意味着“stdin”可能是键盘,也可能是另一个输入流。 (3认同)

Ste*_*mit 7

标准 C 函数是getchar(),在 中声明<stdio.h>。它基本上从一开始就存在。它从标准输入 ( stdin)读取一个字符,这通常是用户的键盘,除非它已被重定向(例如通过 shell 输入重定向字符<或管道)。

getch()getche()是旧的 MS-DOS 函数,在 中声明<conio.h>,并且仍然在 Windows 系统上流行。它们不是标准的 C 函数;它们并非存在于所有系统上。getch立即从键盘读取一个击键,无需等待用户按下 Return 键,也不会响应击键。getche是一样的,除了它回声。据我所知,getch并且getche 总是从键盘读取; 它们不受输入重定向的影响。

问题自然就来了,如果getchar是标准函数,怎么用它来读取一个字符而不等待回车键,或者不回显?这些问题的答案至少有点复杂。(事实上​​,它们足够复杂,我怀疑它们解释了getchand的持久流行getche,如果没有别的,它们很容易使用。)

答案是它getchar无法控制回显和输入缓冲等细节——就 C 而言,这些是较低级别的、依赖于系统的问题。

但是理解getchar假设的基本输入模型是有用的。令人困惑的是,通常有两种不同的缓冲级别。

  1. 当用户在键盘上键入键时,操作系统的终端驱动程序会读取这些键。通常,在其默认模式下,终端驱动程序在键入时立即回显击键(因此用户可以看到他们正在键入的内容)。通常,在其默认模式下,终端驱动程序还支持一定数量的行编辑——例如,用户可以按 Delete 或 Backspace 键来删除意外键入的字符。为了支持行编辑,终端驱动程序通常在输入缓冲区中收集字符. 只有当用户点击 Return 时,该缓冲区的内容才可供调用程序使用。(仅当标准输入实际上是键盘或其他串行设备时才存在此级别的缓冲。如果标准输入已重定向到文件或管道,则终端驱动程序无效并且此级别的缓冲不适用。)

  2. stdio 包从操作系统读取字符到它自己的输入缓冲区。 getchar只需从该缓冲区中获取下一个字符。当缓冲区为空时,stdio 包尝试通过从操作系统读取更多字符来重新填充它。

因此,如果我们跟踪程序getchar第一次调用时开始发生的事情:stdio 发现其输入缓冲区为空,因此它尝试从操作系统读取一些字符,但还没有任何字符可用,因此read调用块。同时,用户可能正在键入一些字符,这些字符在终端驱动程序的输入缓冲区中累积,但用户还没有按回车键。最后,用户点击 Return,被阻塞的read调用返回,将整行的字符返回给stdio,它使用它们来填充其输入缓冲区,然后将第一个字符返回到初始调用getchar,一直耐心等待一直在等待。(然后如果程序getchar第二次或第三次调用,可能还有一些字符——用户键入的行上的下一个字符——在 stdio 的输入缓冲区中可用getchar以立即返回。有关更多信息,请参阅这些C 课程笔记的第 6.2 节。)

但在所有这些中,正如您所看到的,getcharstdio 包无法控制诸如回显或输入行编辑之类的细节,因为这些细节在步骤 1 中的终端驱动程序中更早地在较低级别处理。

因此,至少在类 Unix 操作系统下,如果您想在不等待 Return 键的情况下读取字符,或者控制是否回显字符,您可以通过调整终端驱动程序的行为来实现。细节各不相同,但有一种方法可以打开和关闭回声,还有一种方法(实际上有几种方法)可以打开和关闭输入行编辑。(至少要了解其中的一些细节,请参阅此 SO 问题或旧C 常见问题列表中的问题 19.1。)

当输入行编辑关闭时,操作系统可以立即返回字符(无需等待回车键),因为在这种情况下,它不必担心用户可能输入了错误的需要“采取”的击键后退”用 Delete 或 Backspace 键。(但同理,当一个程序在终端驱动中关闭输入行编辑时,如果想让用户更正错误,就必须实现自己的编辑,因为它会看到---即连续调用getchar将返回——用户的错误字符Delete 或 Backspace 键的字符代码。)