14

feof() は、現在のファイル ポインタの位置の eof をチェックしますか、それとも現在のファイル ポインタの次の位置をチェックしますか?

ご協力いただきありがとうございます !

4

2 に答える 2

39

すべて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関数が役立つことはほとんどありません。

于 2012-09-09T08:30:58.523 に答える
5

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 を返します。_IOEOFfeof

上記からわかるようにfeof、ファイルの最後を超えて最初に文字を読み込もうとすると (またはライブラリ関数が代わりに試行します)、 は true を返します。これは、さまざまな機能の動作に微妙な影響を及ぼします。数字1. でその文字を読み取った後、フラグが設定されていないためgetcfeofは false を返します。_IOEOFファイルの末尾を超えて読み取ろうとした人はまだいません。getc再度呼び出すと、フラグreadの設定である が呼び出され、 true が返されます。ただし、 を使用して同じファイルから数値を読み取った後、はすぐに true を返します。_IOEOFfeoffscanf("%d", &n)feoffscanf整数の追加の桁を読み取ろうとしました。

于 2012-09-09T09:08:57.407 に答える