查看 stdio.h 可以看到如下定义:

#define  EOF  (-1)

#define  _IOEOF  0x0010 
#define  feof(_stream)  ((_stream)->_flag & _IOEOF)

由此可以看出,这两种方式的原理是不同的。

在这里先说下EOF和feof()这个两个宏定义,EOF是不可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于EOF时,表示读入的已不是正常的字符而是文件结束符,但这适用对文本文件的读写。在二进制文件中,信息都是以数值方式存在的。EOF的值可能就是所要处理的二进制文件中的信息。这就出现了需要读入有用数据却被处理为“文件结束“的情况。为了解决这个问题,C提供了一个feof()函数,可以用它来判断文件是否结束。feof(fp)用于测试fp所指向的文件的当前状态是否为“文件结束”。如果是,函数则返回的值是1(真),否则为0(假)。

C语言支持的是流式文件,它把文件看作由一个一个的字符(字节)数据组成的序列。根据数据的组织和操作形式,可以分为ASCII文件和二进制文件。

ASCII文件又称为文本文件,它是在一个字节的存储单元上存放一个字符(在外存中存放的是该字符的ASCII码,每个字符将占一个字节)。

二进制文件是把内存中的数据按其在内存中的存储格式在磁盘上原样保存。 

对字符而言,由于其外存存储格式和内存表示格式相同,所以,在外存上也存放每个字符的ASCII码。

但是说EOF只能用于文本文件,其实不然,这点不是特别的准确,还要看定义的变量的类型。

下面这段程序对文本文件和二进制文件都可以:

int c;
while((c=fgetc(fp)) != EOF)
{
printf("%X/n", c); 
}
如果读到了FF,由于c定义为int型,所以实际上c=0x000000FF,不等于EOF(-1=0xFFFFFFFF),因此不会误判为文件结尾。

但是如果把c定义为char类型,就有可能产生混淆了。
char c;
while((c=fgetc(fp)) != EOF)
{
printf("%X/n", c); 
}
因为文本文件中存储的是ASCII码,而ASCII码中FF代表空值(blank),一般不使用,所以如果读文件返回了FF,说明已经到了文本文件的结尾。但是如果是二进制文件,其中可能会包含FF,因此不能把读到EOF作为文件结束的条件,此时只能用feof()函数。

在VC里,只有当文件位置指针(fp->_ptr)到了文件末尾,然后再发生读/写操作时,标志位(fp->_flag)才会被置为含有_IOEOF。然后再调用feof(),才会得到文件结束的信息。

因此,如果运行如下程序:
char c;
while(!feof(fp))
{
c = fgetc(fp);
printf("%X/n", c); 
}
会发现多输出了一个FF,原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。这样就多输出了一个-1(即FF)。

正确的写法应该是:
char c;
c = fgetc(fp);
while(!feof(fp))
{
printf("%X/n", c); 
c = fgetc(fp);
}

feof()和EOF的用法(转载)的更多相关文章

  1. 理解feof与EOF

    feof(feof msdn) feof用于判断文件结尾.头文件<cstdio>.使用方法是feof(fp),fp为指向需要判断的文件的指针.如果不到文件结尾,返回0值:如果是文件结尾,返 ...

  2. C# DataSet与DataTable的区别和用法 ---转载

    C# DataSet与DataTable的区别和用法 转载:https://www.cnblogs.com/liuyi-li/p/6340411.html DataSet是数据集,DataTable是 ...

  3. shell基础之EOF的用法

    一.EOF的用法 EOF是(END Of File)的缩写,表示自定义终止符.既然自定义,那么EOF就不是固定的,可以随意设置别名,在linux按ctrl-d 就代表EOF. EOF一般会配合cat能 ...

  4. 移动端下拉刷新,iScroll.js用法(转载)

    本文转载自: iScroll.js 用法参考 (share)

  5. 深入PHP EOF(heredoc)用法详解

    介绍下使用EOF heredoc方式,输出长段内容的方法, <?php $name = '姓名'; print <<<EOT <html> <head> ...

  6. ES6 Promise 用法转载

    Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方法,原型上有then.catch等同样很眼熟的方法. 那就new一个 var p = new Promise( ...

  7. python---map 用法 [转载]

    map()函数 map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回. 1.当seq只 ...

  8. c++ 网络编程(七) LINUX下 socket编程 基于套接字的标准I/O函数使用 与 fopen,feof,fgets,fputs函数用法

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9614820.html 一.标准I/O 1,什么是标准I/O?其实是指C语言里的文件操作函数,如 ...

  9. SQL中CASE 的用法 转载

    sql语言中有没有类似C语言中的switch case的语句?? 没有,用case   when   来代替就行了.              例如,下面的语句显示中文年月 select getdat ...

随机推荐

  1. SQL学习之去重复查询

    下面是一张表的数据

  2. api文档生成工具 C#

    要为编写的程序编写文档,这是件费力气的事,如果能自动生成就好了. 不怕做不到,就怕想不到.这不,搜索到了Sandcastle 比较好的参考文章: 1.Sandcastle官方网址: http://sh ...

  3. Oracle排序

    按照拼音排序 SELECT * FROM TEAM ORDER BY NLSSORT(排序字段,'NLS_SORT = SCHINESE_PINYIN_M') 按照笔画排序 SELECT * FROM ...

  4. 重启sql server服务两种方式

    1.第一种重启SQl server的方法 点击左侧的数据库重启 如图 右击有个重启操作 2.第二个重启sql server方法

  5. C++/C#结构体转化-传string给C++

    此例是把C#结构传给C++ C++: typedef struct VidyoClientInEventGroupChat_ { /*! Message (contents) to be sent t ...

  6. A - 数塔

    A - 数塔 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Statu ...

  7. Linux学习之守护进程详解

    Linux系统守护进程详解                                                              ---转自:http://yuanbin.blog ...

  8. 在sqlite中使用索引

    出处: 网络 1)Sqlite不支持聚集索引,android默认需要一个_id字段,这保证了你插入的数据会按“_id”的整数顺序插入,这个integer类型的主键就会扮演和聚集索引一样的角色.所以不要 ...

  9. robot framework环境搭建和简单示例

    环境搭建 因为我的本机已经安装了python.selenium.pip等,所以还需安装以下程序 1.安装wxPythonhttp://downloads.sourceforge.net/wxpytho ...

  10. uva 10779 Collectors Problem 网络流

    链接 一共有n个人, m种收藏品, 每个人拥有的收藏品的种类和个数都是不相同的. 假设2-n这些人都只和1互相交换, 比例是1:1, 并且, 2-n这些人, 只换自己现在没有的, 如果他现在有第二种, ...