C语言文件操作解析(五)之EOF解析

在C语言中,有个符号大家都应该很熟悉,那就是EOF(End of File),即文件结束符。但是很多时候对这个理解并不是很清楚,导致在写代码的时候经常出错,特别是在判断文件是否到达文件末尾时,常常出错。

1.EOF是什么?

在VC中查看EOF的定义可知:

#define EOF     (-1)

EOF只是代表一个整形常量-1。因此很多人认为在文件的末尾存在这个结束标志EOF,这种观点是错误的。事实上在文件的末尾是不存在这个标志的。那么有人会问那下面的程序如何解释?

    char ch;    while((ch=fgetc(fp))!=EOF)    {        printf("%c\n",ch);    }

书上都通过这样的代码去判断是否读取到文本文件末尾,就是当读取到EOF的时候就结束操作。这种理解是错误的。

先看一下函数fgetc的原型:

int fgetc(FILE *fp);

事实上在fgetc函数内部,每次都是读取一个字节的数据,而且这一个字节的数据是以unsigned即无符号型处理的,然后将这一个字节的数据赋给一个int型变量作为返回值返回,因此无论从文件中读取的是什么数据,作为无符号型赋值给一个int型变量,返回值不可能是负数。比如当读取到数据0xFA时,因为是以无符号处理的,因此在将0xFA赋值给int型变量的时,int型变量的高位是填充0的(为什么填充0,跟汇编语言里面的符号扩展类似,在后面会提到),因此返回的结果是0X00 00 00 FA,始终不会是负数.而若读取到文件末尾的时候,即没有数据可供读取的时候,那么返回EOF,即-1,这个-1是一个int型常量,二进制表示是0x FF FF FF FF。

上面的代码具有很大的局限性,因为其只能判断是否到达文本文件的末尾,而不能对二进制文件进行准确的判断。因为正常情况下,文本文件中无论如何是无法读取到-1(0x FF)这个数据,因此可以判断。但是对于二进制文件不同,很可能读到的一个字节的数据就是0xFF,那么返回值此时就是-1,但是此时还未到达文件末尾,造成错误的判断。

那么有没有办法解决?可以将ch定义为int型即可。

下面来比较一下下面这段程序和上面程序在执行时的区别。

    int ch;    while((ch=fgetc(fp))!=EOF)    {        printf("%c\n",ch);    }

假如在文件中读取到的数据是0xFA。

那么对于上面一段程序的执行过程是:

将0xFA先赋值给一个int型变量(假如是a),那么此时a为0x 00 00 00 FA,当将返回值a返回给变量ch时,由于ch是char型的,只有8位,那么只将a的低8位赋给ch,那么此时ch为0x FA,而ch是作为有符号处理的,那么此时ch的值肯定是负数。

而若将ch定义为int型,执行过程为:

将0xFA先赋值给一个int型变量(假如是a),那么此时a为0x 00 00 00 FA,当将返回值a返回给变量ch时,由于ch也是int型的,因此ch为0x 00 00 00 FA,是一个正数,两段程序执行得到的结果完全不同。

下面看一下若读取到的数据是0x FF(此时未到文件末尾)时,是什么结果。

若ch为char型,则当将返回值0x 00 00 00 FF返回时,取低8位赋给ch,那么此时ch为-1,此时会误判为到达文件末尾;

而若ch为int型,则当将返回值0x 00 00 00 FF返回时,ch的值为0x 00 00 00 FF,此时ch不为-1,不会误判为文件末尾。

(当然上面所述成立必须是在读取不出错的情况下才成立)

所以很多情况下会用到函数feof.

二.feof

feof函数的原型是

int feof(FILE *fp);

若到达文件末尾则返回一个非零值,否则返回0。

在VC中查看feof函数的定义:

#define _IOEOF          0x0010

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

可知feof函数判断是否到达文件末尾时与_flag这个标志有关。

下面看一下这段程序:

#include<stdio.h>#include<stdlib.h>

int main(void){    FILE *fp;    int ch;    if((fp=fopen("test.txt","w+"))==NULL)    {        printf("can not open file\n");        exit(0);    }    for(ch=65;ch<=70;ch++)    {        fputc(ch,fp);    }    rewind(fp);    while(feof(fp)==0)    {        ch=fgetc(fp);        printf("%0X\n",ch);    }    fclose(fp);    return 0;}

执行结果是:

41
42
43
44
45
46
FFFFFFFF
Press any key to continue

为什么最后打印结果会多打印一个FFFFFFFF?不是只往文件中写入了数据65-70么?

先看一下C++ Reference中关于feof函数的描述(C++ Reference是一个比较好的网站,里面是关于C++所有库函数的描述,网址在博客首页的链接中有,http://www.cplusplus.com/reference/):

Checks whether the End-of-File indicator associated with stream is set, returning a value different from zero if it is.
This indicator is generally set by a previous operation on the stream that reached the End-of-File.

从描述中可知,只有当与文件关联的流到达文件末尾时,此时若再进行读取操作,文件结束的标志(上面所述的_flag)才会被重新置位。

因此在上述程序中,当读取完最后一个字节的数据后,文件结束标志并没有被置位,只有当位置指针到达末尾时,再发生读取操作时,而此时又没有数据可供读取,因此返回-1,所以打印出的结果中会多一个FFFFFFFF,在这之后才会将_flag重新置位,此时feof函数才能检测出已经到达了文件末尾。

那么可以通过下面的办法解决这个问题:

    ch=fgetc(fp);    while(feof(fp)==0)    {        printf("%0X\n",ch);        ch=fgetc(fp);    }

这样就不会多打印一个FFFFFFFF了。

在上面提到汇编语言中符号扩展的问题,其实在C语言中属于数据类型转换的范畴。下面简要说明一下:

符号扩展只针对将字长小的数据赋给字长大的数据时存在,若是字长大的数据赋给字长小的数据,取低位即可。

下面看一段程序:

#include<stdio.h>

int main(void){    unsigned char ch1=0XFF;    char ch2=0XFF;    char ch3=0X73;    int a=ch1;    int b=ch2;    int c=ch3;    printf("%d\n%d\n%d\n",a,b,c);    return 0;}

执行结果为:

255

-1

115

原因是由于ch1、ch2、ch3都是char型变量,只占一个字节,区别在于ch1是无符号的,在将ch1赋值给a时,ch1是看做无符号数据进行处理的,那么在填充a的高位是用0去填充;而对于ch2和ch3都是有符号的,那么在填充高位时就要注意了,若ch2的最高位为0,那么表示ch2是正数,此时填充高位用0填充,而若ch2的最高位为1,则填充高位数据用1填充。

如程序执行的结果所示,由于ch2的最高位为1,那么在填充b的高位的时候会用1去填充,那么b为0X FF FF FF FF;而ch3的最高位为0,那么填充c的高位用0填充,所以c的值为0x 00 00 00 73.

C语言文件操作解析(五)之EOF解析(转载)的更多相关文章

  1. C语言 文件操作(五)

    (1)size_t fread ( void * ptr, size_t size, size_t count, FILE * stream ); 其中,ptr:指向保存结果的指针:size:每个数据 ...

  2. 【转】C语言文件操作解析(三)

    原文网址:http://www.cnblogs.com/dolphin0520/archive/2011/10/07/2200454.html C语言文件操作解析(三) 在前面已经讨论了文件打开操作, ...

  3. go语言文件操作,这期资料比较详细( 欢迎加入go语言群: 218160862 )

    go语言文件操作,这期资料比较详细 欢迎加入go语言群: go语言深圳群 golang深圳 218160862 点击加入 文件操作 func Open(name string) (file *File ...

  4. C 语言文件操作

    C 语言文件操作 1. 数据流:     程序与数据的交互以流的形式进行.fopen 即打开数据流,fclose 即刷新数据流.     所谓数据流,是一种抽象,表示这段数据像流一样,需要逐步接收,不 ...

  5. C语言文件操作

    C语言文件操作,以下以基本的例子和说明来展开怎么通过C语言来进行文件操作. 操作文件,我们得需要知道什么?当然是路径和文件名. 首先我需要知道我操作的文件在哪里,叫什么名字.在C语言中还存在一个打开方 ...

  6. C语言文件操作函数

    C语言文件操作函数大全 clearerr(清除文件流的错误旗标) 相关函数 feof表头文件 #include<stdio.h> 定义函数 void clearerr(FILE * str ...

  7. C语言文件操作函数大全(超详细)

    C语言文件操作函数大全(超详细) 作者: 字体:[增加 减小] 类型:转载 本篇文章是对C语言中的文件操作函数进行了详细的总结分析,需要的朋友参考下   fopen(打开文件)相关函数 open,fc ...

  8. C语言文件操作 FILE结构体

    内存中的数据都是暂时的,当程序结束时,它们都将丢失.为了永久性的保存大量的数据,C语言提供了对文件的操作. 1.文件和流 C将每个文件简单地作为顺序字节流(如下图).每个文件用文件结束符结束,或者在特 ...

  9. C语言文件操作相关函数

    在实际应用中,我们往往需要对文件进行操作,下面我将介绍C语言的一些关于操作文件的函数. 一.计算机文件 计算机文件是以计算机硬盘为载体存储在计算机上的信息集合,是存储在某种长期储存设备上的一段数据流. ...

随机推荐

  1. J - Air Raid - hdu 1151(最小边覆盖)

    题意:给一个有向无环图,求出来最少需要几个士兵可以遍历所有的边. 分析:有向无环图的最小边覆盖 = 点数 - 最大匹配数 为什么是这样的公式??可以思考一下,如果这N个点之间没有边,是不是应该有N个士 ...

  2. 10个提升iOS开发效率的必用工具

    Xcode插件 几乎所有开发者都知道Alcatraz是一个开源的包管理工具,可以让我们更轻松地管理各种插件.接下来就介绍下我的最推荐的10个插件: 10.HOStringSense 在编辑字符串的时候 ...

  3. windows 编程 —— 菜单以及其他资源

    目录: 1.资源的种类 2.资源的定义方法(IDE:VC++) 3.资源的获取 4.资源的使用与消息处理函数   1.资源的种类 windows 的常用的资源包括:图示 .游标. 字符串. 自订资源. ...

  4. struts2中修改Action后刷新浏览器后不能及时更新

    在学习strut2的时候,发现如果修改配置文件中Action的时候,刷新浏览器并不能加载修改后的Action,只能关闭服务,重新开启server才能获取到,上网找了许多资料后发现只要在配置文件中加上下 ...

  5. Android中自定义Activity和Dialog的位置大小背景和透明度等

    1.自定义Activity显示样式 先在res/values下建colors.xml文件,写入: view plainprint? 1. <?xml version="1.0" ...

  6. python django model类型摘要

    V=models.CharField(max_length=None[, **options]) #varchar V=models.EmailField([max_length=75, **opti ...

  7. word2vec浅析

    本文是參考神经网络语言模型.word2vec相关论文和网上博客等资料整理的学习笔记.仅记录 自己的学习历程,欢迎拍砖. word2vec是2013年google提出的一种神经网络的语言模型,通过神经网 ...

  8. 从零开始写一个Tomcat(壹)

    Tomcat是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,也是一个servlet容器的优秀解决方案,做Java web开发的基本上都使用过,但是tomcat大多时间对于我们是一个黑 ...

  9. Java利用Rxtx进行串口通讯

    最近在做传感器数据采集的工作,底层是基于Zigbee的无线传感网络,所有数据采集到Zigbee协调器上然后通知上位机数据采集完成,上位机通过USB转串口去读取数据就可以了.那么问题来了,如何进行串口通 ...

  10. 九宫重拍(bfs + 康拓展开)

    问题描述 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的局面记为:12 ...