遇到的一个神奇的C编程问题

[复制链接]
1385|39
 楼主 | 2016-5-11 15:45 | 显示全部楼层 |阅读模式
问题不好表述,看个例子应该会好理解些:typedef unsigned int u16;
typedef unsigned char u8;


void Test1(void)
{
    u16 temp_u16;

    u8 temp1_u8,temp2_u8;

    temp1_u8 = 2;
    temp2_u8 = 2;

    temp_u16 = temp1_u8<<8 + temp2_u8;
}

void Test2(void)
{
    u16 temp_u16;

    u8 temp1_u8,temp2_u8;

    temp1_u8 = 2;
    temp2_u8 = 2;

    temp_u16 = temp1_u8;
    temp_u16 <<=8;
    temp_u16 +=temp2_u8;
}


这两个函数最后计算出的temp_u16数值是不一样的,Test1函数中的temp_u16为何和预期的不一样?
按说temp_u16是u16变量,在运算前,temp1_u8和temp2_u8应该会被隐式转换成u16再进行计算。
我想可能是隐式转换的规则没弄清,有哪位比较清楚该问题的麻烦给点意见呗。
| 2016-5-11 18:24 | 显示全部楼层
那本书上说的,,这样的隐式转换
http://blog.csdn.net/miaouu/article/details/5213042
| 2016-5-11 18:36 | 显示全部楼层
第一个,TEMP_U16 2,第二个,2*256+2
| 2016-5-11 18:41 | 显示全部楼层
左边跟右边没有关糸,TEMP1_U8 <<8,equal:  u8 temp;
temp=temp1;
temp<<=8;//overflow,temp=0
| 2016-5-11 18:52 | 显示全部楼层
是你自已没有理解好那段话。
| 2016-5-11 18:55 | 显示全部楼层
最后赋值时,右边转换成左边的类型,而没有说中间计算过程。
| 2016-5-11 19:28 | 显示全部楼层
第一答案应该是0x800,  第二答案应该是0x202。运算符号的优先顺序是“+”先,“<<”后。
“temp_u16 = temp1_u8<<8 + temp2_u8;”改为“temp_u16 = (temp1_u8<<8) + temp2_u8;”应该就对了。

评论

datouyuan 2016-5-11 20:09 回复TA
赞一个.我是搞怕了,只要看到这类表达式都会下意识增加括号,而懒得去查那个优先. 
| 2016-5-11 20:11 | 显示全部楼层
nethopper 发表于 2016-5-11 19:28
第一答案应该是0x800,  第二答案应该是0x202。运算符号的优先顺序是“+”先,“ ...

验证过吗?我怎么觉得不加括号时,移位运算符优先级本来就比算术运算符高呢?
我怎么觉得你说的这个结果依然是错的呢~
| 2016-5-11 20:15 | 显示全部楼层
nethopper 发表于 2016-5-11 19:28
第一答案应该是0x800,  第二答案应该是0x202。运算符号的优先顺序是“+”先,“ ...

应该是7楼说得对.
我也碰到几次类似的疑难杂症,我是搞怕了.
以后只要看到这类表达式都会下意识增加括号,而懒得去查那个优先.
| 2016-5-11 20:25 | 显示全部楼层
江枫渔火 发表于 2016-5-11 20:11
验证过吗?我怎么觉得不加括号时,移位运算符优先级本来就比算术运算符高呢?
我怎么觉得你说的这个结果 ...

你不信可以验证一下看,我刚在网上找了两个不同的网站验证查询运算符号的顺序问题,供参考,两个表格基本上是一致的。一般编程的时候,有时候也记不太清楚,加括号比较保险。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
| 2016-5-12 07:58 | 显示全部楼层
很基础的问题,非常不建议将这样的语句写成一句,分开写,即明白清晰,也不用死记优先级等。为何喜欢这样写呢?

效率是一样的
| 2016-5-12 07:59 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
| 2016-5-12 08:10 | 显示全部楼层
第一,temp_u16 = temp1_u8<<8 + temp2_u8; 运算优先级上有问题,“+”会先运算,然后“<<”,最后“=”
第二,即使是"temp_u16 = (temp1_u8<<8) + temp2_u8; ",存在类型隐式转换问题,也不一定对,至少不一定在所有编译环境都对;

最好写成:temp_u16 = ((u16)temp1_u8<<8) + temp2_u8;
或者干脆采用第二种写法;
这两种写法,对编译器而言,除了Keil的0级优化不好说,一般会编译成一样的汇编代码的。
| 2016-5-12 08:32 | 显示全部楼层
不懂优先级,就使劲加括号就行了......
| 2016-5-12 08:35 | 显示全部楼层
u8    temp1_u8  <<8位 和
u16  temp_u16  <<8位 是不一样的
| 2016-5-12 08:40 | 显示全部楼层
能写的通俗易懂吗,这样写为哪般
| 2016-5-12 09:55 | 显示全部楼层
用强制转换, 无问题
temp_u16 = (u16 *)(temp1_u8<<8 + temp2_u8);
| 2016-5-12 11:19 | 显示全部楼层
对于移位操作符 << 或者 >>,这是双目操作符,有两个操作数。在C标准中规定,移位时被移位数(左操作数)有个类型转换,规则如下:
如果左操作数当前类型的有符号数范围小于高于其类型一级(int > short > char)的有符号数的范围,那么操作数当前类型的无符号数会转换为高一级类型的有符号数。在这里就是,unsigned char类型的数据左移8位,类型转换为short类型,然后unsigned char类型的数据再加short类型的数据,最终结果就是一个有符号的short类型的数据。
我也遇到过一样的问题,h t t p :  / / note.youdao.com/share/?id=207bd80acb67bfe4919cc9c1006772f6&type=note

没权限发URL,坑
| 2016-5-12 14:14 | 显示全部楼层
不要想当然得那么美   编译器优化级别不一样都有可能不一样的结果 你还是老老实实的先保证中间不溢出的好
 楼主 | 2016-5-12 14:33 | 显示全部楼层
zxqchongchi 发表于 2016-5-12 11:19
对于移位操作符 >,这是双目操作符,有两个操作数。在C标准中规定,移位时被移位数(左操作数)有个类型转 ...

你好。我看了下你的链接所贴出的笔记,大致理解是:移位操作前,会转换成范围大一些的有符号数进行运算,所以如果移位操作前,数据的最高位为1,如0xF0,移位操作后编程有符号数:0xF000,反而成负数了。但这样来看:02<<8+02的数据还是应该为:0x0202,但实际并非如此。是哪儿有问题吗?另这个移位符运算的类型转换资料有更具体的吗?
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式
我要创建版块 申请成为版主

论坛热帖

关闭

热门推荐上一条 /4 下一条

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