feof() は、現在のファイル ポインタの位置の eof をチェックしますか、それとも現在のファイル ポインタの次の位置をチェックしますか?
ご協力いただきありがとうございます !
feof() は、現在のファイル ポインタの位置の eof をチェックしますか、それとも現在のファイル ポインタの次の位置をチェックしますか?
ご協力いただきありがとうございます !
すべてFILE
のストリームには、呼び出し元が既にファイルの末尾を超えて読み取ろうとしたかどうかを示す内部フラグがあります。feof
そのフラグを返します。このフラグは、現在のファイル位置がファイルの末尾にあるかどうかを示すのではなく、以前の読み取りがファイルの末尾を超えて読み取ろうとしたかどうかのみを示します。
例として、2 バイトを含むファイルを読み取るときに何が起こるか見てみましょう。
f = fopen(filename, "r"); // file is opened
assert(!feof(f)); // eof flag is not set
c1 = getc(f); // read first byte, one byte remaining
assert(!feof(f)); // eof flag is not set
c2 = getc(f); // read second byte, no bytes remaining
assert(!feof(f)); // eof flag is not set
c3 = getc(f); // try to read past end of the file
assert(feof(f)); // now, eof flag is set
これが、ファイルを読み取るときに次の eof を使用する間違った方法である理由です。
f = fopen(filename, "r");
while (!feof(f)) {
c = getc(f);
putchar(c);
}
仕組みfeof
上、ファイルの終わりフラグはgetc
、ファイルの終わりを超えて読み取ろうとしたときに 1 回だけ設定されます。getc
その後、文字ではない が返さEOF
れ、ループ構築によってputchar
それを書き出そうとするため、エラーまたはガベージ出力が発生します。
すべての C 標準ライブラリ入力メソッドは、成功または失敗の指示を返します。ファイルの末尾を超えて読み取ろうとした場合、または読み取り中にエラーが発生した場合getc
は、特別な値を返します。EOF
特別な値は、ファイルの終わりとエラーで同じです。ここで、適切な使用法
feof
が登場します。これを使用して、ファイルの終わりとエラーの状況を区別できます。
f = fopen(filename, "r");
c = getc(f);
if (c == EOF) {
if (feof(f))
printf("it was end-of-file\n");
else
printf("it was error\n");
}
FILE
エラー状況
のオブジェクトには、別の内部フラグがあります: ferror
. 多くの場合、「ファイルの終わりではない」よりもエラーをテストする方が明確です。C でファイルを読み通す慣用的な方法は次のようになります。
f = fopen(filename, "r");
while ((c = getc(f)) != EOF) {
putchar(c);
}
if (ferror(f)) {
perror(filename):
exit(EXIT_FAILURE);
}
fclose(f);
(簡潔にするために、いくつかのエラー チェックはここの例から省略されています。)
このfeof
関数が役立つことはほとんどありません。
feof
実装方法を知ることで、がどのように機能するかをよりよく理解できます。これは、第 7 版の Unix stdio ライブラリが実装する方法の簡略化されたバージョンですfeof
。最新のライブラリは非常に似ており、スレッドセーフ、効率の向上、およびよりクリーンな実装を提供するコードを追加しています。
extern struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
char _flag;
char _file;
} _iob[_NFILE];
#define _IOEOF 020
#define feof(p) (((p)->_flag&_IOEOF)!=0)
#define getc(p) (--(p)->_cnt>=0? *(p)->_ptr++&0377:_filbuf(p))
int
_filbuf(FILE *iop)
{
iop->_ptr = iop->_base;
iop->_cnt = read(fileno(iop), iop->_ptr, BUFSIZ);
if (iop->_cnt == 0) {
iop->_flag |= _IOEOF;
return(EOF);
}
return(*iop->_ptr++ & 0377);
}
stdio ライブラリは、 が指す内部バッファを含む構造体を各ファイルで維持します_base
。バッファ内の現在の文字は で示され_ptr
、使用可能な文字数は に含まれてい_cnt
ます。などのgetc
多くの高レベル機能のベースとなるマクロはscanf
、バッファから文字を返そうとします。バッファが空の場合、それ_filbuf
を埋めるために呼び出します。 _filbuf
順番に呼び出しますread
。Ifread
が 0 を返す場合、これ以上データが利用できないことを意味し、フラグ_filbuf
を設定します。これは、呼び出すたびにチェックして true を返します。_IOEOF
feof
上記からわかるようにfeof
、ファイルの最後を超えて最初に文字を読み込もうとすると (またはライブラリ関数が代わりに試行します)、 は true を返します。これは、さまざまな機能の動作に微妙な影響を及ぼします。数字1
. でその文字を読み取った後、フラグが設定されていないためgetc
、feof
は false を返します。_IOEOF
ファイルの末尾を超えて読み取ろうとした人はまだいません。getc
再度呼び出すと、フラグread
の設定である が呼び出され、 true が返されます。ただし、 を使用して同じファイルから数値を読み取った後、はすぐに true を返します。_IOEOF
feof
fscanf("%d", &n)
feof
fscanf
整数の追加の桁を読み取ろうとしました。