fgetc与EOF的错综复杂关系

关注嵌入式安卓物联网行业及人才培养,每日更新,欢迎订阅及留言讨论~~~

作者:倪键树,嵌入式安卓物联网讲师。



fgetcEOF的错综复杂关系

1fgetc对字节的读取

在正常的情况下,fgetc unsigned char 的方式读取文件流,扩展为一个整数,并返回。换言之,fgetc 从文件流中取一个字节,并加上24个零,成为一个小于256的整数,然后返回。


int c;

while ((c = fgetc(rfp))!= -1) // -1就是 EOF

fputc (c,wfp);


解析:上面 fputc 中的 c 虽然是整数,但在 fputc将其写入文件流之前,又把整数的高24位去掉了,因此 fgetcfputc 配合能够实现文件复制。到目前为止, c 定义为char仍然是可行的,但下面我们将看到,把 c 定义为 int 是为了能正确判段文件是否结束的,而char则不能判断文件是否结束。


2、判断文件结束


多数人认为文件中有一个EOF,用于表示文件的结尾。但这个观点实际上是错误的,在文件所包含的数据中,并没有什么文件结束符。fgetc 而言,如果不能从文件中读取,则返回一个整数 -1,这就是所谓的EOF返回 EOF 无非是出现了两种情况,一是文件已经读完; 二是文件读取出错,反正是读不下去了。


注意:在正常读取的情况下,返回的整数均小于2560x0~0xFF而读不出返回的是-10xFFFFFFFF但是假如你用fputc 0xFFFFFFFF 往文件里头写,24位被屏蔽,写入的将是 0xFF


3、将c定义 int读取0xFF 会使我们误判为结束吗?


不会,前提是接收返回值的 c 要按原型定义为 int


如果下一个读取的字符将为 0xFF


int c;

c = fgetc (rfp);//本来读取为0xFF,自动扩展c = 0x000000FF;

if (c != -1)  // 当然不相等, -1 0xFFFFFFFF

fputc (wfp);  //所以即使读取了OXFF 复制也成功!


字符0xFF其本身并不是EOF


4、将c定义 char,若读取为0xFF,复制将失败。


假定下一个读取的字符为 0xFF 则:


char c;

c = fgetc (rfp);// fgetc(rfp)的值扩展为 0x000000FF强转char型变为c = 0xFF

if (c != -1)  // 字符0xFF与整数-1比较,c 被扩展为0xFFFFFFFF(即-1),所以,条件成立,文件复制提前退出。

C被扩展为0xFFFFFFFF,由下面代码可以验证:

#include <stdio.h>

int main()

{

char c;

   c = -1;

printf("%x",c);

   return 0;

}

得到的结果为ffffffff

while((c=fgetc(rfp))!=EOF) 中的判别条件成立,文件复制结束! 意外中止,复制失败!


5、将c定义为 unsigned char;


当读到文件末尾,返回 EOF也就是-1时,


unsigned char c;

c = fgetc (rfp);// fgetc (rfp)的值为EOF,即-1,即0xFFFFFFFF降格为字节, c=0xFF

if ( c!= -1) // c 被扩展为 0x000000FF(即255),永远不会等于 0xFFFFFFFF


所以这次虽然能正确复制 0xFF但却不能判断文件结束。事实上,在 cunsigned char时,c != -1 是永远成立的,一个高质量的编译器,比如 gcc会在编译时指出这一点。


注:关于charsigned char unsigned char 的区别在哪里?”请看后边解析!


6、为何需要feof?

FILE *fp;

fp 指向一个很复杂的数据结构, feof 是通过这个结构中的标志来判断文件是否结束的。如果文件用 fgetc 读取,刚好把最后一个字符读出时, fp 中的EOF标志不会打开,如果这时用feof判断,将会得到文件尚未结束的结论,fgetc取得最后一个错误的-1


fgetc 返回 -1 时,我们仍无法确信文件已经结束,因为可能是读取错误! 这时我们需要 feof ferror


总结:EOF并不是存在于文件中的,而是一种状态,当读到文件末尾或者读取出错时就会返回这个值。(即使读取错误可能也被认为文件结束,所以就需要用feof ferror来判断是不是真的文件结束了)


7getchar(c)的使用


当用getchar(c)时,即使c定义成字符型,也可以结束,主要是c-1比较时,c会从char转换为整型值,同c定义为int


charsignedchar unsigned char 的区别在哪里???

ANSI C 提供了3种字符类型,分别是charsigned charunsigned charchar相当于signed char或者unsigned char,但是这取决于编译器!!!这三种字符类型都是按照1个字节存储的,可以保存256个不同的值:

signedchar取值范围是 -128 127

unsigned char 取值范围是 0 255


但是char究竟相当于signed char呢还是相当于unsigned char呢??对于int类型的有: int==signed int,但是char不能简单以为char==signed char。要确定char究竟等同什么要基于不同的编译器做测试。

大多数机器使用补码来存储整数,在这些机器中按照整数类型存储的-1的所有位均是1,假设我的机器也是如此存储,就能据此判断char究竟是等于signed char还是unsigned char

程序如下:

094106855.png

094129549.png

094153646.png

此可以判断在我的机器上char==signed char

但是绝对不能武断认为char==signed char就像int==signed int一样天经地义,大部分人还是单纯认为char==signed char的,其实换位思考一下就清楚了,c规定了九种不同的整形其中有charsigned char unsihned char,但是只有int 没有 signed int(二者相等),如果简单认为char就是等同于signed char的话那8种不就完事了???

如果编译器支持unsigned charchar的相等同,设置这个选项就会发现char==unsigned char。下面是对这种相等的设置。


-funsigned-char

-fno-signed-char

这两个编译时设定的参数是对char类型进行设置,决定将char类型设置成-unsigned char


-fsigned-char

-fno-unsigned-char

这两个编译时设定的参数是对char类型进行设置,决定将char类型设置成signed char

094244277.png

094307928.png

094422271.png


如此 char就等同于unsigned char

总结:小小的char类型,竟然有如此的玄机,你看明白了吗?!要时刻谨记fgetc的用法,和EOF的理解,写出严谨的程序。


你可能感兴趣的:(eof,fgetc,char型数据揭秘)