scanf何时开始和停止扫描?

Sum*_*Tea 7 c io buffer scanf

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

#include <stdio.h>

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;
}
Run Code Online (Sandbox Code Playgroud)

这是另一个问题,在我禁用输入缓冲之后(只是为了验证结果;我知道我应该在实际中做到这一点,以防它干扰结果),输出是(注意额外的提示):

$ ./ionbf
12(space)(enter)
number: 12
$
$
Run Code Online (Sandbox Code Playgroud)

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

$ ./iofbf
12(space)(enter)
number: 12
$
Run Code Online (Sandbox Code Playgroud)

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

问题是:

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

Jon*_*ler 11

有趣的问题 - 冗长的回答.如有疑问,我正在描述我认为在Unix上发生的事情; 我将Windows留给其他人.我认为行为类似,但我不确定.

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

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

当你点击返回时,内核有4个字符可供发送给任何想要阅读它们的程序:1 2 space return.

在您使用的情况下,通过诸如此类的调用_IONBF将这4个字符一次性读入标准I/O缓冲区.在随后收集的和字符从缓冲区,并把后面的空间到缓冲区.(请注意,内核已将所有四个字符传递给程序.)程序打印其输出并退出.shell恢复,打印提示并等待更多输入可用 - 但是在用户键入另一个输入之前不会有任何输入可用,可能(通常)前面有一些其他字符.stdinread(0, buffer, BUFSIZ)scanf()12spacereturn

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

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

您还可以使用trussstrace类似命令来跟踪程序执行的系统调用,以查看我建议发生的事件的准确性.

  • 我是你的粉丝......真是个答案.晶莹剔透. (2认同)