[英]Why does scanf returns control back to the program on pressing Enter key?
我写了以下程序。
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]);
}
我从键盘输入“3”后跟一个TAB。 什么都没发生。 然后,按Enter键。 我打印“3”,程序结束。
如果“ TAB” [水平标签]和“ Enter” [换行符]都是空白字符,为什么它们的行为不同?
详细信息是特定于操作系统的(因为标准C99不了解终端)。
我假设您使用的是Linux 。
首先, stdio(3)缓冲标准输入流和大多数其他FILE*
流。 您可能尝试使用setvbuf(3)更改它,但这只会影响输出缓冲。
更重要的是,当stdin (实际上是它使用的文件描述符,即STDIN_FILENO
,通常是fileno(stdin)
的值)是一个终端(参见isatty(3)来测试),linux内核通常是行缓冲的终端(所谓的熟化模式 ) - 至少处理退格键。 您可以通过将tty切换到原始模式来更改它(因为像emacs
或vim
或nano
这样的每个编辑器都可以)。 看到这个问题 。 但是你应该在程序退出之前重置熟化模式。
所以在正常情况下,会发生两个级别的缓冲:在内核中用于终端的线路规则,在libc
用于缓冲stdin
在实践中, 如果你想要复杂的终端输入,使用像ncurses或readline这样的库 (不要只使用termios)
另见stty(1) & termios(3) & tty_ioctl(4) ; 阅读ANSI转义码 。
请注意,此行缓冲在两个级别( libc
和内核)特定于ttys。 当stdin
是一个管道(7) (如echo foo | yourprogram
)或一个文件(如你的程序yourprogram < yourinputfile.txt
),事情是不同的。
简而言之,ttys很难理解,因为它们模仿了20世纪50年代到70年代的复杂和神秘的硬件设备。
大多数操作系统缓冲键盘输入,以便它们可以正确处理退格 - 操作系统将输入保持在缓冲区中,并且仅在Enter命中时将其输入到程序中。
大多数操作系统也提供了控制它的方法,但不同操作系统的方式不同。 在POSIX系统上, tcsetattr
命令用于控制此终端缓冲以及许多其他事情。 您可以阅读termios(3)手册页,了解有关它的大量信息。 通过设置非规范模式,您可以获得所需的行为:
#include <termios.h>
#include <unistd.h>
:
struct termios attr;
tcgetattr(0, &attr);
attr.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &attr);
这会导致操作系统立即向你的程序发送每个击键(除了一些特殊的击键,如ctrl-C ),无需等待Enter ,也没有处理退格。
请注意,终端设置在使用相同终端的程序中是持久的,因此您可能希望保存程序启动时的原始设置,并在退出之前将其还原。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.