你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

关于if语句中无符号数取反码,大神来分析一下

[复制链接]
iyumi 提问时间:2018-8-31 09:57 /
本帖最后由 iyumi 于 2018-8-31 11:04 编辑

这个是昨天发的那个问题,链接:https://www.stmcu.org.cn/module/forum/thread-617272-1-1.html
原因找到了,网上搜了一下,也有这个问题的讨论,但是还是不太明白,单独再拿出来,看论坛里的大神能不能解释得更清楚一些,给一个确定的答案
我的代码简化如下:

unsigned char a, b;
a=...;
b=...;
if(a==(~b))
{
    语句1;
}
else
{
    语句2;
}
编译器认为这个if语句永远不会成立,所以把语句1这部分的代码都优化掉了

这个链接:http://ask.csdn.net/questions/643846 中有网友提到:

int main() {
unsigned char te1,te2,te3;
te1 = 0xff;
te2 = 0x00; //te2二进制:00000000
if(te2 == (~te1)){
     te3 = 1;
}
else{
     te3 = 2;
}
printf("%d",te3);//输出:2
printf("%u",(char)(~te1));//无符号char 输出是:0

//无符号char 输出解析:
//te1:0000 0000 0000 0000 0000 0000 1111 1111
//~te1:1111 1111 1111 1111 1111 1111 0000 0000
//~te1强制转换char:0000 0000 所以输出为0
printf("%u",(~te1)); //无符号 输出是:4294967040
//无符号 输出解析:
//te1:0000 0000 0000 0000 0000 0000 1111 1111
//~te1:1111 1111 1111 1111 1111 1111 0000 0000
//~te1=二进制1111 1111 1111 1111 1111 1111 0000 0000=4294967040
printf("%d",(~te1)); //有符号int 输出是:-256
//有符号 输出解析:
//te1:0000 0000 0000 0000 0000 0000 1111 1111
//~te1:1111 1111 1111 1111 1111 1111 0000 0000
//由于:~te1开头为1 是负数 补码输出
//~te1=1000 0000 0000 0000 0000 0000 1111 1111 + 1 = -256
if(-256 == (~te1)){
        te3 = 1;
}
else{
        te3 = 2;
}
printf("%d",te3);//输出:1
//说明在条件语句中(~te1)是按有符号输出 然后在做比较

return 0;


}
疑问:
1、跟这个例子不同的地方是,我的代码中a和b都不是确定的数,编译器怎么就认为一定不能相等呢?
2、b取反后就认为是一个有符号数,那么if语句中就是一个有符号数和无符号数比较,恒不等?


大神们帮忙分析分析



收藏 评论10 发布时间:2018-8-31 09:57

举报

10个回答
wenyangzeng 回答时间:2018-8-31 10:29:30
unsigned char a, b;
无符号变量如何得到负数?
应该定义成 char型的。
す疯Ⅱ恒す 回答时间:2018-8-31 10:35:00
是你用32位机试的吧。在单片机实际的运算中,都会放到寄存器里运行,比较ARM内核的,用R0 R1运算取反,R0 R1都是32位的,取反之后高位都是1,所以是-256.
如果要验证这个问题,你可以用8位单片机再试试,结果应该符合你的预期。
如果还是用32位机做,建议多一个8位无符号变量c、c=~b,然后再比较if(a==c),在赋值的过程中,c只保留低8位。
iyumi 回答时间:2018-8-31 10:38:47
す疯Ⅱ恒す 发表于 2018-8-31 10:35
是你用32位机试的吧。在单片机实际的运算中,都会放到寄存器里运行,比较ARM内核的,用R0 R1运算取反,R0 R ...

我就是用的是8位机才出的问题,STM8S103,昨天论坛里的朋友用STM32编译过第一个链接中的代码,他说没有问题,我没有STM32的板子,没有办法验证,确实用一个中间变量可以解决问题
yu0405jie 回答时间:2018-8-31 10:44:39
C语言中有一种隐式类型转换叫整数提升转换,当对一个unsigned char操作数执行~运算时,由于整数提升转换,最终结果将是一个signed int类型的负值。因此(~b)是一个signed int型变量且为负。
一个无符号的char型变量和一个负值的int型变量相比,应最终都先隐式转化为signed int进行比较,这时候a为正,(~b)为负,肯定不相等了。

点评

是这个原因,学习了  发表于 2018-8-31 11:04
iyumi 回答时间:2018-8-31 10:47:40
wenyangzeng 发表于 2018-8-31 10:29
unsigned char a, b;
无符号变量如何得到负数?
应该定义成 char型的。

是无符号数取反以后最高位为1,以负数的形式储存,这一点32位还好理解,但是我是8位的,就不懂了

定义成char是可以的,但为什么定义成uchar就不行呢?
iyumi 回答时间:2018-8-31 11:03:26
yu0405jie 发表于 2018-8-31 10:44
C语言中有一种隐式类型转换叫整数提升转换,当对一个unsigned char操作数执行~运算时,由于整数提升转换, ...

哦,原来是这样的啊,我还以为8位机uchar只有8bit,取反也没有高位了,终于明白了,非常感谢
stm1024 回答时间:2018-8-31 11:25:51
C语言规范中,对于取反等操作,结果是int32_t的数据类型,测试代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. int main()
  5. {
  6.     uint8_t a=16;
  7.     printf("%d\r\n",sizeof(a));
  8.     printf("%d\r\n",sizeof(~a));
  9.     return 0;
  10. }
复制代码

输出的结果分别是1和4
zhao.zhao 回答时间:2018-8-31 12:29:20
这个问题提的好,解决了一些看似没问题,但容易犯错的地方。以后要注意。
toofree 回答时间:2018-8-31 13:11:05
本帖最后由 toofree 于 2018-8-31 13:33 编辑

参考板凳楼层,
补充一下
在不确定的情况下,可以建一个同类型的中间变量。或者多强制类型转换。
比如
if(te2 == (unsigned char)(~te1))

temp = ~te1;
    if(te2 == temp)

傲游截图20180831131937.png
对于浮点数变量的比较,不要用等于,只能是大于或小于固定精度的数值。
float a=3.141592653589793; 实际上写这么长是无意义的,比较的时候必须有所取舍
比如 if (a>3.14 && a<3.15),
要是只判断 if (a == 3.141592653589793),或者if (a == 3.141593),也不相等的。
傲游截图20180831133317.png


所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
13245底部标题123相同标题
12底部标题123相同标题
33333底部标题123相同序号
3435底部标题-无链接
关注我们
st-img 微信公众号
st-img 手机版