char c; while((c=getchar())!=EOF)

Q: What's wrong with this code?

char c;

while((c = getchar()) != EOF)

A:很多初学者都习惯用char型变量接收getchargetcfgetc等函数的返回值,其实这么做是不对的,并且隐含着足以致命的错误。   

getchar等函数的返回值类型都是int型,当这些函数读取出错或者读完文件后,会返回EOF(在系统中,它并不是存在于文件中任何实际的end-of-file字符,而是没有任何字符可用的信号)EOF是一个宏?,一个区别于getchar返回值的数据,它与所有可能的getchar返回的char值截然不同,标准规定它的值必须是一个int型的负数常量,通常编译器都会把EOF定义为-1问题就出在这里,使用char型变量接收getchar等函数的返回值会导致对EOF的辨认出错,或者把好的数据误认为是EOF,或者把EOF误认为是好的数据。换言之,变量c被声明为char类型,而不是int类型,这意味着c无法容下所有可能的字符,特别是,可能无法容下EOF。所以getchar的返回值必需存储在比char大的变量中。

我们来看下此程序的运行过程。首先,因为fgetc等函数的返回值是int型的,当赋值给char型变量时,会发生降级,从而导致数据截断。

例如:

十进制 |          int        |  char  |
10          | 00 00 00 0A |  0A  |
-1          | FF FF FF FF |  FF  |
-2          | FF FF FF FE |  FE  |

在此,我们假设intchar分别是32位和8位的。由上可得,从int型到char型,损失了3个字节的数据。而当我们要拿char型和int型比较的时候,char型会自动升级为int型。char型升级为int型后的值会因为它到底是signed char还是unsigned char而有所不同。不幸的是,如果我们没有使用signed或者unsigned来修饰char,我们便无从知晓char到底是指unsigned char还是指signed char,因为这是由编译器决定的。不过,无论charsigned的也好,unsigned的也罢,都不能改变使用char型变量接收fgetc等函数的返回值是错误的这个事实。唯一能改变的是该错误导致的后果。

1.     

  |  char |    unsigned    |       signed      |
  |   10   | 00 00 00 0A | 00 00 00 0A |
  |   FF  | 00 00 00 FF | FF FF FF FF |
  |   FE  | 00 00 00 FE | FF FF FF FE |

由上表可知,当charunsigned的时候,其转换为int后的值是正数。也就是说,假如我们把c定义为char型变量,而编译器默认char unsigned char,那么表达式(c=fgetc(fp))!=EOF将永远成立,也就是说以下循环是一个死循环。

2. 

读到这里,可能有些朋友会说:那么我明确把c定义为signed char型的就没问题了吧!很遗憾,就算把c定义为signed char,仍然是错误的。假设fgetc等函数读到一个字节的值为FF,那么返回值就是00 00 00 FF把这个值赋值给 c 后,c的值变成FF然后c的值为了和 EOF 比较,会自动升级为int型的值,也就是FF FF FF FF从而导致表达式(c=fgetc(fp))!=EOF成立,将跳出循环。即读到值为FF的字符,误认为EOF也就是说循环在没有读完文件的情况下提前退出。

永不止步步 发表于01-17 14:43 浏览65207次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:302267个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号