1、前言
EOF其实就是一个宏
#define EOF (-1)
即EOF 的值是占4个字节int,值为0xffffffff;
int fgetc(FILE *stream); //从文件中读字符file get char
成功返回读到的字符,
失败或者读到文件末尾返回EOF;
fgetc函数的返回值是int,此时
取值范围是:0x00 00 00 00 -----0x00 00 00 FF.
读到文件尾:EOF(0xFF FF FF FF)
int ch; //这个地方一定要是int才行!!!!!
while ( ( ch= fgetc(fp) ) != EOF) //不断读取文件直到结束
{
putchar(ch);
}
2、原因分析:
fgetc() 的返回值类型为 int,故要赋值给int类型变量,而不能赋值给char或unsigned char 类型变量?
假设fgetc取的字节是0xff,即返回值是0x000000ff;
1)若是char ch;
while ( ( ch= fgetc(fp) ) != EOF)
是将int类型数据赋值给了char类型,只取后8位,故ch=0xff;
然后,ch与EOF比较,char类型与int类型比较,char会被转化为int,最终 ch变为0xffffffff,与EOF相等,函数退出,误以为到了文件结尾,造成错误。
0x00 00 00 FF------->0x FF--------->0xFF FF FF FF 与-1的编码冲突,会将0xFF 误认为是文件尾。
2)若是unsigned char ch;
while ( ( ch= fgetc(fp) ) != EOF)
0xFF FF FF FF------->0x FF--------->0x00 00 00 FF 与-1(0xFF FF FF FF)不等,即:即使到了文件尾,也与EOF不等。
unsigned char 范围为0-255,文件末尾也无法得到-1,循环不会退出。
3)若是 int ch;
while ( ( ch= fgetc(fp) ) != EOF)
返回值是0x000000ff,赋值给int ch,仍然是0x000000ff,不等于0xffffffff.能正确识别文件末尾。
文件中字符取值范围是:0x00 00 00 00 -----0x00 00 00 FF.
读到文件尾:EOF(0xFF FF FF FF)
不会出现问题。
举例,加深理解:
#include <stdio.h>
int main()
{
int iret = 0xff;
char cret = 0xff;
int num = -1;
printf("iret=%x\n",iret);
printf("cret=%x\n",cret);
printf("num=%x\n",num);
if(iret!=num)
printf("int:iret!=num\n");
else
printf("int:iret==num\n");
if(cret!=num)
printf("char:cret!=num\n");
else
printf("char:cret==num\n");
}

3、总结:
问题的关键是char 类型的数据与int型数据比较的时候,会被强转成int型的32位数据;
而int型数据与int型数据比较则不存在强制位数的转换。
char ch;
while ( ( ch= fgetc(fp) ) != EOF)
是int 转char ;char 转 int------>值发生了变化。
0x000000ff -> 0xff --> 0xffffffff
值由255-------->-1 ------------>-1
其实,不光是字符间的比较,char类型赋值给int型变量,也会出现这个问题:

![]()
也就是说:一个字节的-1,转换成4个字节的-1,是由0xff转换成0ffffffff,而不是转换成0x000000ff(这个不是-1了,而是255了)
小转大,对结果不会产生影响,大转小,对结果会有影响,具体参见本文。
本文深入解析EOF宏定义及fgetc函数的工作原理,强调在读取文件时使用int类型变量接收fgetc函数返回值的重要性,避免char类型可能引发的错误。通过实例演示不同数据类型在比较时的潜在问题。
2387

被折叠的 条评论
为什么被折叠?



