[C言語]getchar()関数は,1文字入力する毎に処理が走る訳ではない

C言語の入門書を見るとgetchar()関数の説明として、”キーボードから1文字入力を読み取る”と書かれていることが多いです。

下記のプログラムは、getchar()の動作確認用プログラムなのですが、実行してみると”キーボードから1文字入力を読み取る”という説明とは異なり、若干の違和感があります。

#inculde <stdio.h>
 
int main( void )
{
    int data;
 
    while( 1 ) {
        // 1文字入力
        data = getchar();
        if ( data == EOF ) {
            break;
        }
 
        // 入力された文字を出力
        putchar( data );
    }
 
}



このプログラムの実行結果は以下の通りです

$ gcc echoback.c -o echoback
 
$ ./echoback 
123
123
^d
 
$



出力結果だけからだと分かり辛いのですが、”キーボードから123と入力後、Enterを押すと文字”123″が表示される”という振る舞いをしています。

getcharの”キーボードから1文字入力を読み取る”をそのまま信じると、1文字単位で入力文字が反映されるはずなので”112233″となりそうなものですが、実際は行単位でのエコーバックになります。
gdbを使ってステップ実行してみると、Enterを入力した時点でwhileが一気に3度回り、その後getchar()の入力待ちとなりました。

gcc -g echoback.c -o echoback
 
gdb echoback
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/user1/work/echoback...done.
(gdb) list
1   #include<stdio.h>
2   
3   int main( void )
4   {
5       int data;
6   
7       while( 1 ) {
8           // 1文字入力
9           data = getchar();
10          if ( data == EOF ) {
 
 
(gdb) b 7                                               #ブレークポイントを7行目にセット
Breakpoint 1 at 0x804841d: file echoback.c, line 7.
(gdb) run
Starting program: /home/user1/work/echoback 
 
Breakpoint 1, main () at echoback.c:9
9           data = getchar();                           #キー入力待ち. 
                                                        #"123Enter"を入力するまで進まない
(gdb) next
123
10          if ( data == EOF ) {
(gdb) next
15          putchar( data );                            #1文字目の出力
(gdb) next
16      }
(gdb) next
 
Breakpoint 1, main () at echoback.c:9
9           data = getchar();                           #ここではキー入力待ちにならない
(gdb) next
10          if ( data == EOF ) {
(gdb) next
15          putchar( data );                            #2文字目の出力
(gdb) next
16      }
(gdb) next
 
Breakpoint 1, main () at echoback.c:9
9           data = getchar();
(gdb) next
10          if ( data == EOF ) {
(gdb) next
15          putchar( data );                            #3文字目の出力
(gdb) next
16      }
(gdb) next
 
Breakpoint 1, main () at echoback.c:9
9           data = getchar();
(gdb) next
10          if ( data == EOF ) {
(gdb) next
15          putchar( data );                            #4文字目の出力(Enter)
(gdb) next
123                                                     #ここで纏めて文字が表示される
16      }
(gdb) next
 
Breakpoint 1, main () at echoback.c:9
9           data = getchar();                           #再度入力待ち
(gdb) nex
Ambiguous command "nex": next, nexti.
(gdb) next



このような振る舞いになるのは、C言語では標準入力(stdin)が入力された文字をバッファリングしており、getchar()関数を使用する場合は、Enterが押されるまでプログラム側ではそのバッファを認識できないのが原因です。

また、標準出力(stdout)も出力バッファがあるので、出力側が1文字単位ではなく1行纏めて出ていたのもこれが原因です。

プログラムの経験がある人から見ると普通の振る舞いですが、C言語で初めてプログラムを学ぶ場合は、都度処理しない事を不思議に思うかもしれません。
コンピュータはCPU内部の計算処理に比べると、入出力処理は非常に時間が掛かるため、処理速度向上のためにこのようなバッファが設けられています。

関連記事

コメントを残す

メールアドレスが公開されることはありません。