現在のC標準で記述されたコードは
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
ループは次のように書き直すことができます
int c;
while (1) {
c = getchar();
if (c != EOF)
putchar(c);
else
break;
}
これは次のように読みます
- 永遠に繰り返す
- 標準入力から入力の次の文字(「バイト」)を取得し、に格納します
c
- 当該文字の読み取り中に例外的な状態が発生しなかった場合
- そうしないと
多くのプログラミング言語は、通常のプログラムフローを中断する例外を発生させることにより、例外条件を処理します。Cはそのようなことをしません。代わりに、失敗する可能性のある関数には戻り値があり、例外的な条件は特別な戻り値によって通知されます。これは、特定の関数のドキュメントから確認する必要があります。の場合getchar
、C11標準のドキュメントには(C11 7.21.7.6p3)と記載されています。
- この
getchar
関数は、が指す入力ストリームから次の文字を返しますstdin
。ストリームがファイルの終わりにある場合、ストリームのファイルの終わりインジケーターが設定され、をgetchar
返しますEOF
。読み取りエラーが発生すると、ストリームのエラーインジケーターが設定され、getchar
が返されますEOF
。
EOF
<0である整数定数であり、通常の戻り値は>=0であると他の場所で述べられています-unsigned char
ゼロは。に拡張されますint
。
ストリームがファイルの終わりにあるということは、すべての入力が消費されたことを意味します。標準入力の場合、Unix / Linux端末でCtrl+を入力し、Windowsコンソールウィンドウで+を入力することにより、キーボードからこれを引き起こすことができます。もう1つの可能性は、プログラムがキーボードからではなくファイルまたはパイプから入力を受け取ることです。その場合、入力が完全に消費されるたびにファイルの終わりが通知されます。DCtrlZ
cat file | ./myprogram
また
./myprogram < file
上記のフラグメントが示すように、実際には2つの異なる条件がgetchar
返される可能性があります。ファイルの終わりに到達したか、実際のエラーが発生したEOF
かのいずれかです。これは、戻り値だけから推測することはできません。代わりに、関数とを使用する必要があります。標準入力でファイルの終わりに達した場合、真の値を返します。エラーが発生した場合はtrueを返します。feof
ferror
feof(stdin)
ferror(stdin)
実際のエラーが発生した場合、errno
によって定義された変数<errno.h>
にはエラーコードが含まれます。この関数perror
を使用すると、人間が読める形式のエラーメッセージにプレフィックスを付けて自動的に表示できます。したがって、例を次のように拡張できます。
#include <stdio.h>
#include <errno.h> // for the definition of errno
#include <stdlib.h> // for exit()
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
if (feof(stdin)) {
printf("end-of-file reached\n");
exit(0);
}
else if (ferror(stdin)) {
printf("An error occurred. errno set to %d\n", errno);
perror("Human readable explanation");
exit(1);
}
else {
printf("This should never happen...\n");
exit('?');
}
}
ファイルの終わりをトリガーするには、^D
Linuxの新しい行でCtrl + D(ここではとして表示)を使用します。
% ./a.out
Hello world
Hello world
^D
end-of-file reached
(ここでの入力がラインバッファリングされているため、入力が出力のあるライン内でインターリーブされていないことに注意してください)。
同様に、パイプラインを使用しても同じ効果を得ることができます。
% echo Hello world | ./a.out
Hello world
end-of-file reached
エラーをトリガーするのは少し注意が必要です。bash
シェルでは、コマンドラインに追加するzsh
ことで、標準入力を閉じて、どこからも入力されないようにすることができます。<&-
% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor
不正なファイル記述子、または標準入力-ファイル記述子番号0がまったく開かれなかったため、無効であったことをEBADF
意味します。
エラーを生成するもう1つの楽しい方法は、ディレクトリから標準入力を読み取ることです。これによりEISDIR
、Linuxでerrnoが設定されます。
% ./a.out < /
An error occurred. errno set to 21
Human readable explanation: Is a directory
実際には、の戻り値putchar
もチェックする必要があります。同様にEOF
、エラーが発生した場合、または次のように記述された文字が返されます。
while ((c = getchar()) != EOF) {
if (putchar(c) == EOF) {
perror("putchar failed");
exit(1);
}
}
そして今、標準出力をにリダイレクトすることでこれをテストできます/dev/full
-しかし、落とし穴があります-標準出力はバッファリングされているので、プログラムの最後ではなく、すぐにバッファをフラッシュさせるのに十分な書き込みが必要です。から無限のゼロバイトを取得します/dev/zero
:
% ./a.out < /dev/zero > /dev/full
putchar failed: No space left on device
int
PSの戻り値を格納するには、常に型の変数を使用することが非常に重要ですgetchar()
。文字を読み取っても、// plainの使用は常に間違っていsigned
unsigned
char
ます。