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

关于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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版