假设我在c中有一个简单的代码,我被要求输入我的年龄,然后程序将打印出我的答案。当我运行这个程序时,它会说"输入你的年龄"。然后(使用scanf)等待我输入一个数字,比如40。我按下键盘上的4和0键。但是,我必须按下回车键,以便程序注册我所写的内容并终止scanf。为什么我必须按回车键?为什么不按空格键或者shift键呢?我想scanf("%d", &age);将消耗并存储所有数字,直到找到非数字,然后终止。但是如果我写40a或400而不是40,我仍然需要按enter键来结束scanf函数并让程序继续。为什么?它只是一个定义吗,就像你在谷歌上搜索东西时必须在搜索栏里按回车键一样?我希望你明白我的意思!
如果让我猜的话,我会说这和定义有关,但是,我也不知道。我读了一个类似问题的另一个答案,但是我有一半不懂。
这与程序完全无关。当您在终端上输入时,有两种模式可以操作:原始模式或熟模式。在原始模式下,终端驱动程序将在输入字符时将字符发送到stdin。在熟食模式下,它将等待,直到它看到一个回车,然后发送整行。熟模式还做其他事情,如解释光标键和其他特殊字符。
默认情况下,您的终端处于烹煮模式。
这通常是一件好事。如果你输入40
作为你的数字,然后意识到你犯了一个错误,应该输入30
,在烹饪模式下,你可以按两次退格键,然后输入30
,当你按回车键时,程序只会看到30
。在原始模式下,你必须自己处理退格,你的程序会看到40<backspace><backspace>30
。
在类unix操作系统上,使用tcgetattr()和tcsetattr()在终端上设置原始模式。这里有一些代码可以做到这一点。它是用Swift写的,但对于C程序员来说应该是相当容易理解的。
// Creates a new empty termios structure
var originalTermios: termios = termios()
// Gets the current settings for the terminal. Note: fileHandle is a Unix
// file descriptor, not a FILE* For stdin, it is conventionally 0
// It's assumed that you already know the file descriptor is a
// terminal.
if tcgetattr(fileHandle, &originalTermios) == -1 {
throw LineNoise.Error.generalError("Could not get term attributes")
}
// defer is a Swift keyword that makes the following block run at
// the end of the scope. In this case it restores the original settings
defer {
// Disable raw mode
_ = tcsetattr(fileHandle, TCSAFLUSH, &originalTermios)
}
// Make a copy of the existing terminal settings
var raw = originalTermios
// Set/reset the necessary bits to go into raw mode.
// Other stuff happens here too, e.g. signal handling stuff.
#if os(Linux) || os(FreeBSD)
raw.c_iflag &= ~UInt32(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
raw.c_oflag &= ~UInt32(OPOST)
raw.c_cflag |= UInt32(CS8)
raw.c_lflag &= ~UInt32(ECHO | ICANON | IEXTEN | ISIG)
#else
raw.c_iflag &= ~UInt(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
raw.c_oflag &= ~UInt(OPOST)
raw.c_cflag |= UInt(CS8)
raw.c_lflag &= ~UInt(ECHO | ICANON | IEXTEN | ISIG)
#endif
raw.c_cc.16 = 1
// Set the attributes
if tcsetattr(fileHandle, Int32(TCSAFLUSH), &raw) < 0 {
throw LineNoise.Error.generalError("Could not set raw mode")
}
// Here, do stuff with the file descriptor in raw mode.
// Note that using standard buffered IO functions might be unpredictable