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

How feof() works in C

提问人:Alfred James 提问时间:9/9/2012 更新时间:9/9/2012 访问量:15824

问:

feof() 是否检查 eof 的当前位置 filepointer 或检查当前 filepointer 旁边的位置?

感谢您的帮助!

C 文件处理 FEOF

评论


答:

42赞 user25148 9/9/2012 #1

每个流都有一个内部标志,指示调用方是否已尝试读取文件末尾。 返回该标志。该标志不指示当前文件位置是否为文件末尾,仅指示上一次读取是否尝试读取超过文件末尾。FILEfeof

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

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);
}

由于工作方式的原因,只有在尝试读取文件末尾时才会设置文件末尾标志。 然后返回 ,即 不是字符,循环构造导致尝试编写它 out,导致错误或垃圾输出。feofgetcgetcEOFputchar

每个 C 标准库输入法都会返回成功或 失败:如果它试图读取超过 文件末尾,或者读取时出现错误。特殊值为 文件末尾和错误也是如此,这就是正确的使用方式:您可以使用它来区分文件末尾和错误 情况。getcEOFfeof

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");
}

对于错误情况的对象,还有另一个内部标志:。测试错误通常比“不是文件末尾”更清晰。 在 C 语言中读取文件的惯用方法是这样的:FILEferror

f = fopen(filename, "r");
while ((c = getc(f)) != EOF) {
    putchar(c);
}
if (ferror(f)) {
    perror(filename):
    exit(EXIT_FAILURE);
}
fclose(f);

(为简洁起见,此处的示例中省略了一些错误检查。

该函数很少有用。feof

评论

1赞 9/9/2012
对不起,很兴奋,把它扩大了一点。
0赞 Alfred James 9/9/2012
文件 *f,*g;整数 c1,c2,c3;f = fopen(“测试.txt”, “r”);g=fopen(“t.txt”,“w”);c1 = getc(f);printf(“%d\n”,c1);普特克(C1,G);c2 = getc(f);printf(“%d\n”,c2);普特克(C2,g);c3 = getc(f);printf(“%d\n”,c3);普特克(C3,g);返回 0;
0赞 Alfred James 9/9/2012
尝试了此代码,但没有得到任何垃圾值或错误。为什么会这样
0赞 9/9/2012
阿尔弗雷德,我得到一个垃圾字节作为 t.txt 中的第三个也是最后一个字节。你的 test.txt 真的是两个字节长,而不是三个字节吗?(在 Unix 中使用 'echo -n 12 > test.txt' 创建 test.txt,并注意 -n 选项)。
0赞 Alexander Suraphel 10/19/2012
Herber Shildt 在他的书中建议以错误的方式使用该函数,而不是 EOF。
5赞 Diomidis Spinellis 9/9/2012 #2

通过了解它是如何实现的,您可以更好地了解它是如何工作的。这是第 7 版 Unix stdio 库如何实现的简化版本。现代库非常相似,添加的代码提供线程安全、更高的效率和更简洁的实现。feoffeof

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 库为每个文件维护一个结构,其中包含由 指向的内部缓冲区。缓冲区中的当前字符由 指向,可用字符数包含在 中。宏是许多更高级别功能的基础,例如 ,尝试从缓冲区返回字符。如果缓冲区为空,它将调用以填充它。 反过来会调用 .如果返回 0,这意味着没有更多数据可用,将设置标志,每次调用它时都会检查它以返回 true。_base_ptr_cntgetcscanf_filbuf_filbufreadread_filbuf_IOEOFfeof

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