7

scanfキーが押されたときに入力のスキャンが開始されるようEnterです。これを以下のコードで確認したいと思います (簡単にするために、エラー チェックと処理を省略しました)。

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

ここで別の問題が発生します。入力バッファリングを無効にした後 (結果を確認するためです。結果に干渉する場合に備えて、実際には絶対にそうすべきではないことがわかっています)、出力は次のようになります (余分なプロンプトに注意してください)。

$ ./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 がインストールされたマシンの 2 つの異なるマシンでテストしましたが、結果はどちらも同じでした。

問題は次のとおりです。

  1. 入力バッファリングが有効な場合と無効な場合の異なる動作を説明するにはどうすればよいですか?
  2. 元の問題に戻ると、scanfはいつユーザー入力のスキャンを開始しますか? 文字を入力した瞬間?それとも、行が完了するまでバッファリングされますか?
4

1 に答える 1

11

興味深い質問 — 長い答えです。疑わしい場合は、Unix で何が起こると思うかを説明しています。Windows は他の人に任せます。動作は似ていると思いますが、よくわかりません。

を使用する場合は、システム コールを使用してsetvbuf(stdin, NULL, _IONBF, 0)stdinストリームが一度に 1 文字ずつ読み取られるようにします。またはを使用read(0, buffer, 1)して実行すると、ストリームを管理するコードは、一度にさらに多くのバイトを読み取ろうとします ( を使用する場合、または使用しない場合は、指定したバッファーのサイズまで)。これらの観察と入力のスペースは、何が起こるかを説明するための鍵です。あなたの端末は通常または正規の入力モードにあると仮定しています —それについての議論については、正規と非正規の端末入力を参照してください。_IOFBF_IOLBFsetvbuf()BUFSIZ

Return を入力するまで、ターミナル ドライバが文字を使用できないことは間違いありません。これにより、入力時にバックスペースなどを使用して行を編集できます。

Return キーを押すと、カーネルは 4 文字を読み取りたいプログラムに送信できます: 1 2 space return.

を使用していない場合、これらの 4 文字はすべて、 などの呼び出しによって_IONBF標準 I/O バッファに一度に読み込まれます。次に、 、および の文字をバッファから収集し、スペースをバッファに戻します。(カーネルが 4 文字すべてをプログラムに渡したことに注意してください。) プログラムは出力を出力して終了します。シェルは再開し、プロンプトを出力して、さらに入力が可能になるのを待ちます — しかし、ユーザーがおそらく (通常は) 他の文字の前に別の を入力するまで、入力は利用できません。stdinread(0, buffer, BUFSIZ)scanf()12spacereturn

を使用している場合_IONBF、プログラムは文字を 1 つずつ読み取ります。read()1 つの文字を取得する呼び出しを行い、 1;を取得します。別の呼び出しを行い、 ;read()を取得します。2別のread()呼び出しを行い、文字を取得しspaceます。(カーネルにはまだreturn数字を解釈するためのスペースは必要ないので、プッシュバック バッファーに戻し (プッシュバック バッファーには少なくとも 1 バイトのスペースがあることが保証されています)、次の標準 I の準備ができています。 /O 読み取り操作、および戻ります。プログラムは出力を出力して終了します。シェルが再開し、プロンプトを出力して、端末から新しいコマンドを読み取ろうとします。カーネルは待機中の改行を返すことを義務付け、シェルは「ああ、それは空のコマンドです」と言って、別のプロンプトを表示します。

1 2 x p s return( _IONBF) プログラムに入力することで、これが起こることを示すことができます。これを行うと、プログラムは値 12 と 'x' を読み取り、'ps' と改行はシェルによって読み取られるように残されます。シェルはpsコマンドを実行し (読み取った文字をエコー表示せずに)、プロンプトを表示します。また。

trussまた、またはまたは 同様のコマンドを使用straceして、プログラムによって実行されるシステム コールを追跡し、私が提案することの真実性を確認することもできます。

于 2012-10-17T03:59:12.903 に答える