scanf何时开始和停止扫描?

当按下Enter键时, scanf似乎开始扫描输入,我想用下面的代码validation这一点(为简单起见,我省略了错误检查和处理)。

 #include  int main(int argc, char **argv) { /* disable buffering */ setvbuf(stdin, NULL, _IONBF, 0); int number; scanf("%d", &number); printf("number: %d\n", number); return 0; } 

这是另一个问题,在我禁用输入缓冲之后(只是为了validation结果;我知道我应该接下来 – 实际上从不这样做,以防它干扰结果),输出是(注意额外的提示):

 $ ./ionbf 12(space)(enter) number: 12 $ $ 

这与输入缓冲启用时的输出不同(无额外提示):

 $ ./iofbf 12(space)(enter) number: 12 $ 

启用缓冲区时似乎消耗了新行字符。 我在两台不同的机器上进行了测试,一台安装了gcc 4.1.2和bash 3.2.25,另一台安装了gcc 4.4.4和bash 4.1.5,结果两者相同。

问题是:

  1. 如何在启用和禁用输入缓冲时解释不同的行为?
  2. 回到原来的问题, scanf什么时候开始扫描用户输入? 角色进入的那一刻? 或者它是否缓冲直到一条线完成?

有趣的问题 – 冗长的回答。 如有疑问,我正在描述我认为在Unix上发生的事情; 我将Windows留给其他人。 我认为这种行为会很相似,但我不确定。

使用setvbuf(stdin, NULL, _IONBF, 0) ,使用read(0, buffer, 1)系统调用强制stdin流一次读取一个字符。 当您使用_IOFBF_IOLBF运行时,管理流的代码将尝试一次读取更多字节(如果使用setvbuf() ,则最多可读取缓冲区的大小,如果不使用,则为BUFSIZ )。 这些观察结果加上输入中的空间是解释所发生情况的关键。 我假设您的终端处于正常或规范输入模式 – 请参阅Canonical与非规范终端输入以进行讨论。

在输入return之前,终端驱动程序不能使任何字符可用是正确的。 这允许您在键入时使用退格等编辑行。

当你点击返回时,内核有4个字符可以发送到任何想要读取它们的程序: 1 2 空格 返回

使用_IONBF的情况下,通过调用read(0, buffer, BUFSIZ)将这4个字符一次性读入stdin的标准I / O缓冲区。 然后scanf()从缓冲区收集1,2空格字符,并将空间放回缓冲区。 (请注意,内核已将所有四个字符传递给程序。)程序打印其输出并退出。 shell恢复,打印提示并等待更多输入可用 – 但是在用户键入另一个返回之前不会有任何输入,可能(通常)前面有一些其他字符。

在使用_IONBF的情况下,程序一次读取一个字符。 它进行read()调用以获取一个字符并获得1 ; 它进行另一次read()调用并得到2 ; 它进行另一个read()调用并获取空格字符。 (注意内核仍然有返回就绪和等待。)它不需要空间来解释数字,所以它将它放回到它的回推缓冲区中(保证在后推中至少有一个字节的空间)缓冲区),为下一个标准I / O读操作做好准备,并返回。 程序打印输出并退出。 shell恢复,打印提示,并尝试从终端读取新命令。 内核要求返回正在等待的换行符,shell会说“哦,这是一个空命令”并给你另一个提示。

您可以通过输入1 2 x p s 返回到您的( _IONBF )程序来certificate这是发生的事情。 当你这样做时,你的程序读取值12和’x’,留下’ps’和shell读取换行符,然后执行ps命令(不回显它读取的字符),然后再次提示。

您还可以使用trussstrace或类似命令来跟踪程序执行的系统调用,以查看我建议发生的真实性。