feof() 在 C 中的工作原理

Posted

技术标签:

【中文标题】feof() 在 C 中的工作原理【英文标题】:How feof() works in C 【发布时间】:2012-09-02 11:43:59 【问题描述】:

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

感谢您的帮助!

【问题讨论】:

【参考方案1】:

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

【讨论】:

抱歉,有点激动,扩展了一下。 文件 *f,*g;诠释 c1,c2,c3; f = fopen("test.txt", "r"); g=fopen("t.txt","w"); c1 = getc(f); printf("%d\n",c1); putc(c1,g); c2 = getc(f); printf("%d\n",c2); putc(c2,g); c3 = getc(f); printf("%d\n",c3); putc(c3,g);返回 0; 试过这段代码,但没有得到任何垃圾值或错误。为什么会这样 Alfred,我得到一个垃圾字节作为 t.txt 中的第三个和最后一个字节。你的 test.txt 真的是两个字节长,而不是三个字节吗? (在 Unix 中使用 'echo -n 12 > test.txt' 创建 test.txt,并注意 -n 选项)。 Herber Shildt 在他的书中建议以错误的方式使用函数而不是 EOF。【参考方案2】:

通过了解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。在您使用getc 读取该字符后,feof 将返回 false,因为未设置 _IOEOF 标志;还没有人试图读过文件的末尾。再次调用getc 将导致调用read,设置_IOEOF 标志,这将导致feof 返回true。但是,在使用 fscanf("%d", &n) 从同一文件中读取数字后,feof 将立即返回 true,因为 fscanf 将尝试读取整数的其他数字。

【讨论】:

以上是关于feof() 在 C 中的工作原理的主要内容,如果未能解决你的问题,请参考以下文章

python中的函数生成器的工作原理

Docker工作原理

RS232接口和RS485接口 工作原理及特点。。要详细的。。。谢谢

ADB工作原理

std::lock_guard 示例,解释其工作原理

关于TTL电路工作原理,求详细解答