您的位置:首页 > 其它

fgetc与EOF的错综复杂关系

2015-06-15 09:39 295 查看
1、fgetc对字节的读取

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

intc;

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

        fputc (c,wfp);

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

2、判断文件结束

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

注意:在正常读取的情况下,返回的整数均小于256,即0x0~0xFF。而读不出返回的是(-1)0xFFFFFFFF。但是假如你用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,但却不能判断文件结束。事实上,在 c为unsigned char时,c != -1 是永远成立的,一个高质量的编译器,比如gcc会在编译时指出这一点。

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

6、为何需要feof?

FILE *fp;

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

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

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

7、getchar(c)的使用

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

char、signed char 和 unsigned char 的区别在哪里???

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

signed char取值范围是 -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:

程序如下:



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

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

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

-funsigned-char 

        -fno-signed-char 

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

-fsigned-char 

        -fno-unsigned-char 

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



如此 char就等同于unsigned char了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: