什么时候scanf函数启动和停止扫描? [英] When does scanf start and stop scanning?

查看:333
本文介绍了什么时候scanf函数启动和停止扫描?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这似乎 scanf函数开始扫描输入时<大骨节病>输入键pressed,我想用$ C,以验证该低于$ C(我消除错误检查和处理简单)。

 的#include&LT;&stdio.h中GT;INT主(INT ARGC,字符** argv的){
    / *禁用缓存* /
    setvbuf用来(标准输入,NULL,_IONBF,0);
    INT编号;    scanf函数(%d个,&安培;号码);
    的printf(数:%d \\ n,编号);    返回0;
}

下面谈到的另一个问题,当我禁止输入缓冲(只是为了验证结果,我知道我应该下到永远做到这一点在的情况下,实际上它干扰的结果),输出(注意额外的提示)

  $ ./ionbf
12(空间)(输入)
号码:12
$
$

启用输入缓冲时,这是从输出不同的(没有额外的提示):

  $ ./iofbf
12(空间)(输入)
号码:12
$

这似乎使缓冲区时新行字符被消耗。我在两台不同的机器,用gcc 4.1.2和安装的bash 3.2.25,其他用gcc 4.4.4和bash 4.1.5测试,结果是两个相同的。

的问题是:


  1. 如何在输入缓冲启用和禁用?
  2. 解释不同的行为
  3. 回到最初的问题,什么时候 scanf函数开始扫描用户输入?当下一个字符输入?抑或是缓冲,直到一行完成?


解决方案

有趣的问题 - 长篇大论的回答。如有疑问,我描述我认为发生在Unix;我离开的Windows给其他人。我认为,行为有异曲同工之处,但我不知道。

当您使用 setvbuf用来(标准输入,NULL,_IONBF,0),会强制标准输入流中读取一次一个字符用阅读(0,缓冲,1)系统调用。当你运行 _IOFBF _IOLBF ,那么code管理流将尝试读取更多的字节在同一时间(最多,如果你使用你提供的缓冲区的大小 setvbuf用来() BUFSIZ 如果您别)。这些观察以及你的输入空间的关键是解释发生了什么。我假设你的终端处于正常或规范输入模式 - 见<一href=\"http://stackoverflow.com/questions/358342/canonical-vs-non-canonical-terminal-input/358381#358381\">Canonical VS为这一点。

的讨论非规范端子输入

您是正确的,终端驱动程序不提供任何字符,直到您键入的回报。这使您可以用退格键等您键入的编辑就行了。

当你打回,内核提供4个字符发送到想读他们的任何程序:<大骨节病> 1 <大骨节病> 2 <大骨节病>空格 <大骨节病>返回

在你在哪里的情况下的的使用 _IONBF ,这4个字符都是一次读取到标准的I / O缓冲区标准输入通过调用如阅读(0,缓冲,BUFSIZ)。在 scanf()的然后收集<大骨节病> 1 的<大骨节病> 2 ,并从<大骨节病>空格字符缓冲器,并且该空间把回缓冲器。 (注意,内核已经全部四个字符传递给程序)程序打印输出并退出。外壳简历,打印提示并等待更多的输入可用于 - 但不会有任何可用的输入,直到用户类型另一个<大骨节病>返回,可能(通常)$ P $一些pceded其他字符。

在的使用 _IONBF

在那里你的的情况下,程序读取字符一次。它使一个阅读()呼吁得到一个字符,得到<大骨节病> 1 ;它使另一个阅读()通话并获取<大骨节病> 2 ;它使另一个阅读()通话并获取<大骨节病>空格字符。 (注意,内核仍具有<大骨节病>返回准备和等待。)它并不需要的空间间preT的数量,因此它把它放回其推回缓冲区(有保证要空间在回缓冲区的至少一个字节),准备下一个标准的I / O读操作,并返回。该程序将打印输出并退出。外壳简历,打印提示,并试图从终端读取新的命令。内核通过返回正在等待换行责成,和外壳会说噢,那是一个空的命令,并为您提供了另一个提示。

您可以证明这一点是打字<大骨节病> 1 <大骨节病> 2 <大骨节病> X <大骨节病> P <大骨节病>取值 <大骨节病>返回您( _IONBF )计划。当你这样做,你的程序读取值12和'X',把'PS'和换行符,由外壳,然后将执行被阅读 PS 命令(不附和,它读取字符),然后再次提示。

您也可以使用桁架 strace的或类似的命令来跟踪你的执行的系统调用节目看什么,我建议情况的真实性。

It seems scanf begins scanning the input when the Enter key is pressed, and I want to verify this with the code below (I eliminated error checking and handling for simplicity).

#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;
}

Here comes another problem, after I disable input buffering (just to verify the result; I know I should next-to-never do that in reality in case it interferes the results), the output is (note the extra prompt):

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

which is different from the output when input buffering is enabled (no extra prompt):

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

It seems the new line character is consumed when buffer enabled. I tested on two different machines, one with gcc 4.1.2 and bash 3.2.25 installed, the other with gcc 4.4.4 and bash 4.1.5, and the result is the same on both.

The problems are:

  1. How to explain the different behaviors when input buffering is enabled and disabled?
  2. Back to the original problem, when does scanf begin scanning user input? The moment a character is entered? Or is it buffered until a line completes?

解决方案

Interesting question — long-winded answer. In case of doubt, I'm describing what I think happens on Unix; I leave Windows to other people. I think the behaviour would be similar, but I'm not sure.

When you use setvbuf(stdin, NULL, _IONBF, 0), you force the stdin stream to read one character at a time using the read(0, buffer, 1) system call. When you run with _IOFBF or _IOLBF, then the code managing the stream will attempt to read many more bytes at a time (up to the size of the buffer you provide if you use setvbuf(), or BUFSIZ if you don't). These observations plus the space in your input are key to explaining what happens. I'm assuming your terminal is in normal or canonical input mode — see Canonical vs non-canonical terminal input for a discussion of that.

You are correct that the terminal driver does not make any characters available until you type return. This allows you to use backspace etc to edit the line as you type it.

When you hit return, the kernel has 4 characters available to send to any program that wants to read them: 1 2 space return.

In the case where you are not using _IONBF, those 4 characters are all read at once into the standard I/O buffer for stdin by a call such as read(0, buffer, BUFSIZ). The scanf() then collects the 1, the 2 and the space characters from the buffer, and puts back the space into the buffer. (Note that the kernel has passed all four characters to the program.) The program prints its output and exits. The shell resumes, prints a prompt and waits for some more input to be available — but there won't be any input available until the user types another return, possibly (usually) preceded by some other characters.

In the case where you are using _IONBF, the program reads the characters one at a time. It makes a read() call to get one character and gets the 1; it makes another read() call and gets the 2; it makes another read() call and gets the space character. (Note that the kernel still has the return ready and waiting.) It doesn't need the space to interpret the number, so it puts it back in its pushback buffer (there is guaranteed to be space for at least one byte in the pushback buffer), ready for the next standard I/O read operation, and returns. The program prints its output and exits. The shell resumes, prints a prompt, and tries to read a new command from the terminal. The kernel obliges by returning the newline that is waiting, and the shell says "Oh, that's an empty command" and gives you another prompt.

You can demonstrate this is what happens by typing 1 2 x p s return to your (_IONBF) program. When you do that, your program reads the value 12 and the 'x', leaving 'ps' and the newline to be read by the shell, which will then execute the ps command (without echoing the characters that it read), and then prompt again.

You could also use truss or strace or a similar command to track the system calls that are executed by your program to see the veracity of what I suggest happens.

这篇关于什么时候scanf函数启动和停止扫描?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆