搜索
bottom↓
回复: 40

相同的代码,不同的结果

[复制链接]

出0入0汤圆

发表于 2011-3-1 13:37:35 | 显示全部楼层 |阅读模式
程序运行后,变量 c 的结果是多少?

void main(void)
{
   unsigned char a,b,c;
   a = 0x55;
   b = 0xaa;
   if (a == ~b)
   {
     c = 0;
   }
   else
   {
     c = 1;
   }

   while(1);
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入296汤圆

发表于 2011-3-1 13:40:29 | 显示全部楼层
这个貌似和编译器有关系的……
未经验证,但是猜测貌似有的编译器会把~b计算为0xFF55

出0入0汤圆

 楼主| 发表于 2011-3-1 13:49:17 | 显示全部楼层
回复【1楼】 Gorgon Meducer 傻孩子
------------------------------------------
是啊,刚被这问题搞晕了。在Keil C51中 ~b 被认为是 0x55, 在IAR for 430 中被认为是 0xff55。
为什么没有统一的标准呢?

出0入0汤圆

发表于 2011-3-1 13:58:40 | 显示全部楼层
回复【1楼】Gorgon Meducer 傻孩子
-----------------------------------------------------------------------

切中要害

出0入0汤圆

发表于 2011-3-1 14:00:23 | 显示全部楼层
都不会出现这种情况.楼上两人想错了.

~b肯定是0x55,如果哪个编译器是误认为0xff55,哪就是编译器的bug
注意,这里b被定义为char

所以结果c = 0

出0入0汤圆

发表于 2011-3-1 14:09:35 | 显示全部楼层
~b 如果按标准的话,应该是0xffffffaa
位运算时,先转换为int,再进行运算。

所以,与位运算有关的,都要自己强制转换。

MISRC  标准里面有一条规则是讲到这点的。

出0入0汤圆

发表于 2011-3-1 14:10:38 | 显示全部楼层
楼上,在PC或者其他32位系统里面的一般char是16位的

出0入0汤圆

发表于 2011-3-1 14:18:09 | 显示全部楼层
回复【2楼】cowboy
-----------------------------------------------------------------------
是啊,刚被这问题搞晕了。在Keil C51中 ~b 被认为是 0x55, 在IAR for 430 中被认为是 0xff55。
为什么没有统一的标准呢?

------------------------------------
IAR是对的。KEIL是错的。

出0入0汤圆

发表于 2011-3-1 15:49:01 | 显示全部楼层
回复【2楼】cowboy
回复【1楼】 gorgon meducer 傻孩子
------------------------------------------
是啊,刚被这问题搞晕了。在keil c51中 ~b 被认为是 0x55, 在iar for 430 中被认为是 0xff55。
为什么没有统一的标准呢?
-----------------------------------------------------------------------

51是8位机,430是16位机.....不过还是很奇怪的说

出0入0汤圆

发表于 2011-3-1 22:17:23 | 显示全部楼层
这个问题 [上官金虹]  很有研究,见这里,还有这里

出0入0汤圆

发表于 2011-3-1 22:39:54 | 显示全部楼层
回复【4楼】tiantian2011
都不会出现这种情况.楼上两人想错了.
~b肯定是0x55,如果哪个编译器是误认为0xff55,哪就是编译器的bug
注意,这里b被定义为char
所以结果c = 0
-----------------------------------------------------------------------

同意,又不是int
char 就是8bit,int才与机器有关

出0入0汤圆

发表于 2011-3-1 22:44:24 | 显示全部楼层
keil是对的专业,iar你选对目标机类型没有??
不管是16位机,还是32位机,char就应该是8bit.

出0入0汤圆

 楼主| 发表于 2011-3-1 23:10:11 | 显示全部楼层
回复【9楼】shark
-----------------------------------------------------------------------
谢谢,和我的问题很相似。


回复【10楼】dengting 守望者
-----------------------------------------------------------------------
我一开始的观点与你相同,认为变量为8位,取反后也应该是8位。
网上一些资料:
A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted to int; otherwise the value is converted to unsigned int. This process is called integral promotion.

在运算表达式中,char会提升为int再进行运算,这样看来IAR是对的,KEIL是错的,但是,KEIL这么多年了,不至于有这样的错误吧。

出0入0汤圆

发表于 2011-3-11 00:13:07 | 显示全部楼层
OK,先记住你的话,但暂时还不相信!

出0入0汤圆

发表于 2011-3-11 05:16:20 | 显示全部楼层
"(a==~b)"

the relevant section in C is type promotion. essentially, any char type is promoted to int before any operations. int in this case is a word type.

so in the case above, b is first converted to int, then ~ is applied to that int type, and converted back to a char type before a comparison is made with a.

in this case, the compiler should conclude that a equals ~b.

出0入0汤圆

发表于 2011-3-11 05:17:37 | 显示全部楼层
"楼上,在PC或者其他32位系统里面的一般char是16位的"

char / short / long are defined in C as 8/16/32 bit types.

unfortunately, int is undefined in C, is thus implementation specific.

出0入4汤圆

发表于 2011-3-11 08:01:52 | 显示全部楼层
Keil C51对标准C的扩充和改动非常大,在中断在改变的全局变量不需要用volatile就是一个例子。char一定是8位的,short只是规定不能大于int的位数,long不能小于int的位数。它们和int一样,由编译器决定位数。

出0入0汤圆

发表于 2011-3-11 08:29:27 | 显示全部楼层
这种问题已经说过N遍了.

根据标准C,char本质上没有算术与逻辑运算.
所有char的算术与逻辑运算,将自动提升为int,或者unsigned int的算术与逻辑运算.
(这叫整型提升).

对于~运算符号,标准C要求操作数至少为int.(其他运算符如+,-,*,/都有类似规定)
换句话说,char根本就不能直接进行~运算操作.

但是,char硬是要参与运算,改如何处理呢?
标准C采用变通的办法,自动把char提升至int,或者unsigned int,满足运算符的操作数的要求,
这样char才能参与运算.

如果int能表示所有char的范围,则char将提升至int.
如果不能,则提升至unsigned int.

通常int的位数比char多,int能表示所有char的范围,所以一般char都会提升至int.
但是也有例外,如果char的位数与int相同,且char是无符号,int就无法表示所有char的范围,
那么char将提升至unsigned int.

通常情况,int位数>char的位数,有:
char a;
~a的结果就是~((int)a)的结果.
除了KEIL C51(非常不遵守标准的C编译器),其他编译器如IAR,GCC,VC,C++Builder,KEIL MDK都遵守这条规则.

出0入0汤圆

发表于 2011-3-11 09:01:03 | 显示全部楼层
这个就是没有按MISRA C标准编程出现的 各种貌似问题的问题。

下列来自MISRA C规范

*位运算中符号的改变:当位运算符应用在无符号短整型时,整数提升会有某些特别不利
的反响。比如,在一个unsigned char 类型的操作数上做位补运算通常会产生其值为负的
(signed)int 类型结果。在运算之前,操作数被提升为int 类型,并且多出来的那些高位
被补运算置1。那些多余位的个数,若有的话,依赖于int 的大小,而且在补运算后接右
移运算是危险的。

规则10.5(强制): 如果位运算符 ~ 和 << 应用在基本类型为unsigned char 或unsigned
short 的操作数,结果应该立即强制转换为操作数的基本类型。

则 6.1(强制): 单纯的 char 类型应该只用做存储和使用字符值。

规则6.2(强制): signed char 和unsigned char 类型应该只用做存储和使用数字值。
有三种不同的 char 类型:(单纯的)char、unsigned char、signed char。unsigned char 和signed
char 用于数字型数据,char 用于字符型数据。单纯char 类型的符号是实现定义的,不应依赖。
单纯 char 类型所能接受的操作只有赋值和等于操作符(=、==、!=)。

规则 6.4(强制): 位域只能被定义为unsigned int 或singed int 类型。

楼主的代码应该写成
if (a == (( unsigned char)(~b)))  // 强制类型转换
或者
if (a == (0xff&(~b)))  // 取有效位

出0入0汤圆

发表于 2011-3-11 09:06:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-11 09:08:39 | 显示全部楼层
一句话:char没有算术与逻辑运算.

出0入0汤圆

 楼主| 发表于 2011-3-11 09:20:46 | 显示全部楼层
谢谢 【17楼】 CC2530 上官金虹 ,看来是被KEIL C51的非标准编译误导了。

出0入0汤圆

发表于 2011-3-12 13:26:49 | 显示全部楼层
上官每学一样东西,就注_册一个马甲(void_c, atmega32,stm32 ...),从0积分开玩,现在得有10个马甲了吧,呵。

出0入0汤圆

发表于 2011-3-12 19:01:28 | 显示全部楼层
确实是值得注意的一个问题。

出0入0汤圆

发表于 2011-3-12 19:19:15 | 显示全部楼层
还真不知道有这回事

出0入0汤圆

发表于 2011-3-12 19:51:39 | 显示全部楼层
学习了.但如果8位机严格按c的标准,效果将大幅下降.

出0入0汤圆

发表于 2011-11-5 20:03:36 | 显示全部楼层
MARK个~
不太喜欢这样的C标准...

出0入0汤圆

发表于 2011-11-5 22:12:56 | 显示全部楼层
mark 整型提升

出0入0汤圆

发表于 2011-11-5 23:49:44 | 显示全部楼层
这个值得学习一下

出0入0汤圆

发表于 2011-11-7 20:14:41 | 显示全部楼层
char类型不是8位的吗?
那么unsigned char应该也是8位,
用调试器估计可以看明白什么问题

出0入0汤圆

发表于 2012-2-22 10:29:58 | 显示全部楼层
2楼LOGO,有周润发的气质

出0入0汤圆

发表于 2012-2-22 10:44:22 | 显示全部楼层
mark~~学习了~~~

出0入0汤圆

发表于 2012-5-4 23:07:37 | 显示全部楼层
学习了,以后编程要注意

出0入0汤圆

发表于 2012-5-5 00:52:59 | 显示全部楼层
mark    应该更新了

出0入0汤圆

发表于 2012-9-13 13:20:47 | 显示全部楼层
学习了! 过瘾!!!

出0入0汤圆

发表于 2012-9-13 13:35:11 | 显示全部楼层
这个我觉得是跟你用 编译器  设置的单片机有关,  如果是16位的单片机,它内部的运算都是16位的,即使你定义的是uchar  ,它还是要占用一个int 的空间,运算也是。   所以编译器也必须要保持这样的习惯去处理,就成了0xff55了。
而keil编51,自然就按51的习惯来编译了啊。

出0入0汤圆

发表于 2012-9-13 13:41:20 | 显示全部楼层
很不懂C,却有想学C,可看得头大!!!

出870入263汤圆

发表于 2014-12-23 19:15:16 | 显示全部楼层
听闻cowboy是个高手,翻到这个帖子了。2011年的啊,看得出高手的成长历程。现在来看这个问题,不再是问题了:整型提升规则。

出0入0汤圆

发表于 2015-1-22 10:10:50 | 显示全部楼层
挖坟,查cowboy的帖子翻到的。整型提升,标准C要求,上个月(去年)刚明白,落后4年啊

出0入0汤圆

发表于 2016-3-29 15:01:02 | 显示全部楼层
学习了.....

出0入0汤圆

发表于 2020-12-3 08:40:57 | 显示全部楼层
学习了,感谢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-18 23:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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