开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 2104|回复: 1
收起左侧

[其它] C/C++误区四:char c = getchar()

[复制链接]
结帖率:50% (2/4)
发表于 2012-8-19 10:46:07 | 显示全部楼层 |阅读模式   湖南省益阳市
许多初学者都习惯用 char 型变量接收 getchar、getc,fgetc 等函数的返 回值,其实这么做是不对的,并且隐含着足以致命的错误。getchar 等函数的返 回值类型都是 int 型,当这些函数读取出错或者读完文件后,会返回 EOF.EOF 是一个宏,标准规定它的值必须是一个 int 型的负数常量。通常编译器都会把 EOF 定义为 -1.问题就出在这里,使用 char 型变量接收 getchar 等函数的返 回值会导致对 EOF 的辨认出错,或者错把好的数据误认为是 EOF,或者把 EOF 误认为是好的数据。例如:
int c;  /* 正确。应该使用 int 型 变量接收 fgetc 的返回值 */
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
如上例所示,我们很多时候都需 要先用一个变量接收 fgetc 等函数的返回值,然后再用这个变量和 EOF 比较, 判断是否已经读完文件。上面这个例子是正确的,把 c 定义为 int 型保证了它 能正确接收 fgetc 返回的 EOF,从而保证了这个比较的正确性。但是,如果把 c 定义为 char 型,则会导致意想不到的后果。
首先,因为 fgetc 等函 数的返回值是 int 型的,当赋值给 char 型变量时,会发生降级,从而导致数 据截断。例如:
---------------------------------
| 十进制 |      int     |  char |
|--------|--------------|--- ----|
|   10   | 00 00 00 0A  |   0A  |
|   -1    | FF FF FF FF  |   FF  |
|   -2   | FF FF FF FE  |    FE  |
---------------------------------
在此,我们假设 int 和 char 分别是 32 位和 8 位的。由上表可得,从 int 型到 char 型,损 失了 3 个字节的数据。而当我们要拿 char 型和 int 型比较的时候,char 型 会自动升级为 int 型。char 型升级为 int 型后的值会因为它到底是 signed char 还是 unsigned char 而有所不同。不幸的是,如果我们没有使用 signed 或者 unsigned 来修饰 char,那么我们无从知晓 char 到底是指 unsigned char 还是指 signed char,因为这是由编译器决定的。不过,无论 char 是 signed 的也好,unsigned 的也罢,都不能改变使用 char 型变量接收 fgetc 等函数的返回值是错误的这个事实。唯一能改变的是该错误导致的后果。前面我 们说了,char 型和 int 型比较时,char 会自动升级为 int,下面我们来看看 signed char 和 unsigned char 在转换成 int 后,它们的值有什么不同:
---------------------------------------
|  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 |
----------------------------- ----------
由上表可知,当 char 是 unsigned 的时候,其转换为 int 后的值是正数。也就是说,假如我们把 c 定义为 char 型变量,而编译器默认 char 为 unsigned char,那么以下表达式将永远成立。
(c = fgetc (fp)) != EOF  /* c 的值永远为正数,而标准规定 EOF 为负数 */
也就是说以下循环是一个死循环。
while ( (c = fgetc(fp)) != EOF )
{
putchar(c);
}
读到这 里,可能有些读者朋友会说:“那么我明确把 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 */
也就是说以下循环在没有读完文件的情况下提前退出。
while ( (c = fgetc(fp)) != EOF )
{
putchar (c);
}
综上所述,使用 char 型变量接收 fgetc 等函数的 返回值是错误的,我们必须使用 int 型变量接收这些函数的返回值,然后判断 接收到的值是否 EOF.只有判断发现该返回值并非 EOF,我们才可以把该值赋值 给 char 型变量。
同理,C++ 中,用 char 型变量接收 cin.get() 的 返回值也是错误的。不过,把 char 型变量当作参数传递给 cin.get 则是正确 的。例如:
char c = cin.get();  // 错误,理由同上
char c;
cin.get(c); // 正确

发表于 2012-8-22 11:11:18 | 显示全部楼层   浙江省温州市
路过看下!!!!!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表