我写了以下程序。
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”[Horizanotal Tab]和“Enter”[Newline]都是空白字符,为什么他们的行为不同?
答案 0 :(得分:4)
详细信息是特定于操作系统的(因为标准C99不了解终端)。
我假设您使用的是 Linux 。
首先,stdio(3)正在缓冲标准输入流和大多数其他FILE*
流。您可能会尝试使用setvbuf(3)更改它,但这只会影响输出缓冲。
更重要的是,当 stdin (实际上它使用的文件描述符,即STDIN_FILENO
,通常是fileno(stdin)
的值)是一个终端(参见{{3测试那个),linux内核通常对终端进行行缓冲(所谓的isatty(3)) - 至少要处理 backspace 键。您可以通过将tty切换为原始模式来更改它(因为emacs
或vim
或nano
等每个编辑器都会这样做。见cooked mode。但是你应该在程序退出之前重置熟化模式。
因此,在正常情况下,会发生两个级别的缓冲:在内核中用于终端的线路规则,在libc
中用于缓冲stdin
阅读this question页面和tty demystified
在实践中,如果您需要复杂的终端输入,请使用某些库,例如Text Terminal HowTo或ncurses (不要只使用termios)
另见readline& stty(1)& termios(3);阅读tty_ioctl(4)。
请注意,此行缓冲在两个级别(libc
和内核)特定于ttys。当stdin
是ANSI escape codes(如echo foo | yourprogram
)或文件(如yourprogram < yourinputfile.txt
)时,情况会有所不同。
简而言之,ttys很难理解,因为它们模仿了20世纪50年代到70年代的复杂而神秘的硬件设备。
答案 1 :(得分:3)
大多数操作系统缓冲键盘输入,以便它们可以正确处理退格键 - 操作系统将输入保存在缓冲区中,只有在 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 ,并且不处理退格。
请注意,终端设置在使用相同终端的程序中是持久的,因此您可能希望保存程序启动时的原始设置,并在退出之前将其恢复。