为什么按 Enter 键后 scanf 将控制权返回给程序?

Pan*_*edi 2 c scanf

我写了下面的程序。

void main()
{
   int   *piarrNumber1   = (int *) calloc(1, sizeof(int));
   int   iUserInput      = 0;

   scanf("%d", &iUserInput);
   piarrNumber1[(sizeof piarrNumber1 / sizeof(int)) - 1] = iUserInput;
   printf("\n%d\n", piarrNumber1[0]);
}
Run Code Online (Sandbox Code Playgroud)

我从键盘输入“3”,然后输入 TAB。什么都没发生。然后,我按 Enter 键。我打印出“3”,程序结束。

如果“TAB”[水平制表符]和“Enter”[换行符]都是空白字符,为什么它们的行为不同?

Bas*_*tch 5

详细信息是特定于操作系统的(因为标准 C99 不了解终端)。

我假设你使用的是Linux

首先,stdio(3)正在缓冲标准输入流和大多数其他FILE*流。您可以尝试使用setvbuf(3)更改它,但这只会影响输出缓冲。

更重要的是,当stdin(实际上是它使用的文件描述符,即STDIN_FILENO通常是 的值fileno(stdin))是终端时(请参阅isatty(3)进行测试),Linux 内核通常对终端进行行缓冲(所谓的熟) mode ) - 至少要处理backspace密钥。您可以通过将 tty 切换到原始模式来更改它(就像每个编辑器喜欢emacsvimnano会做的那样)。看到这个问题。但您应该在程序退出之前重置煮熟模式。

因此,在正常情况下,会发生两个级别的缓冲:在内核中用于终端的线路规则,以及在libc用于缓冲stdin

阅读tty 揭秘页面和文本终端操作指南

在实践中,如果您想要复杂的终端输入,请使用一些库,例如ncursesreadline(不要只使用 termios)

另请参见stty(1) & termios(3) & tty_ioctl(4);了解ANSI 转义码信息。

请注意,此行在两个级别(libc和内核)进行缓冲是特定于 ttys 的。什么时候stdin管道(7)(如echo foo | yourprogram)或文件(如yourprogram < yourinputfile.txt)时,情况有所不同。

简而言之,tty 很难理解,因为它们模仿 20 世纪 50 年代至 1970 年代复杂而神秘的硬件设备。