feof()在C中是如何工作的

时间:2012-09-09 08:29:22

标签: c file-handling feof

feof()是否检查文件指针当前位置的eof或检查当前文件指针旁边的位置?

感谢您的帮助!

2 个答案:

答案 0 :(得分:30)

每个FILE流都有一个内部标志,指示调用者是否已尝试读取文件末尾。 feof返回该标志。该标志不指示当前文件位置是否作为文件的结尾,仅指示先前的读取是否已尝试读取超过文件的末尾。

作为一个例子,让我们看看在读取包含两个字节的文件时会发生什么。

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 尝试读取文件末尾。然后getc将返回EOF,即{} 不是一个字符,循环结构会导致putchar尝试编写它 out,导致错误或垃圾输出。

每个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函数很少有用。

答案 1 :(得分:3)

通过了解feof的实施方式,您可以更好地了解feof的工作原理。以下是第7版Unix stdio库如何实现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); 的简化版本。现代图书馆非常相似,增加了提供线程安全性,提高效率和更清晰实施的代码。

_base

}

stdio库为每个文件维护一个包含_ptr指向的内部缓冲区的结构。缓冲区中的当前字符由_cnt指向,可用字符数包含在getc中。 scanf宏是许多更高级别功能的基础,如_filbuf,它尝试从缓冲区返回一个字符。如果缓冲区为空,它将调用_filbuf来填充它。 read反过来会调用read。如果_filbuf返回0,这表示没有更多数据可用,_IOEOF将设置feof标志,每次调用feof时都会检查该标志返回true。 / p>

正如您从上面可以理解的那样,1将在您第一次尝试读取文件末尾的字符(或库函数代表您尝试)时返回true。这对各种功能的行为有微妙的影响。考虑一个包含单个字符的文件:数字getc。使用feof读取该字符后,_IOEOF将返回false,因为getc标志未设置;没有人试图读过文件的结尾。再次呼叫read将导致调用_IOEOF feof标志的设置,这将导致fscanf("%d", &n)返回true。但是,在使用feof从同一文件中读取数字后,fscanf将立即返回true,因为{{1}}将尝试读取整数的其他数字。