14

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

谢谢你的帮助 !

4

2 回答 2

39

每个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尝试将其写出,从而导致错误或垃圾输出。

每个 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。如果read返回 0,这意味着没有更多数据可用,_filbuf将设置_IOEOF标志,feof每次调用它时都会检查是否返回 true。

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

于 2012-09-09T09:08:57.407 回答