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,结果两者相同。
问题是:
- 如何在启用和禁用输入缓冲时解释不同的行为?
- 回到原来的问题,
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
命令(不回显它读取的字符),然后再次提示。
您还可以使用truss
或strace
或类似命令来跟踪程序执行的系统调用,以查看我建议发生的真实性。