C语言有符号数(signed)和无符号数(unsigned)运算时的转换过程——盲点

复习C语言知识时发现了一个非常有趣的程序:
代码如下:

#include <stdio.h>
int main(int argc, char *argv[])
{
    int a=-8;
    unsigned int b=7; 
    if(a+b>0){
        printf("a+b>0\n");
    }else{
        printf("a+b<=0\n");
    }

    printf("%x\n",(a+b));
    printf("%d\n",(a+b));
    return 0;
}

程序输出结果如下:
在这里插入图片描述
看到这里,大家的第一反应肯定和我一样,-8加上7,应该等于-1,按道理输出的是a+b<=0。然而现实总是相反的,我决定花点时间折腾一下,了解清楚这个程序的来龙去脉。

原因如下:
漏了一个知识点:当表达式中存在 有符号数和无符号数时,有符号数会转换成无符号数参加运算,结果也是一个无符号数。程序中的a就是有符号整型,b是无符号整型。

原码:一个整数,按照绝对值的大小转换成二进制数,最高位为符号位。
反码:将原码除最高位(符号位)外,其余各位按位取反,所得到的二进制码。正数的反码和补码都为原码。
补码:反码最低位加1即为补码。

转换过程:由于计算机内部是以补码的形式进行表达的,先把4字节的a变量原码转换为补码

原码二进制表示反码补码
-81000 10001111 01111111 1000
70000 01110000 01110000 0111

unsigned int是32位的无符号整型,范围是0~232 -1,16进制表示为0xFFFF FFFF,所以int类型的a变量转换为unsigned int类型的16进制表示为0xFFFF FFF8,变量b本身就是unsigned int类型,所以表示为0x0000 0007。

a+b相当于 ————> 0xFFFF FFF8+0x0000 0007=0xFFFF FFFF

得到的0xFFFF FFFF是某个无符号的数的补码,反推回去就可以知道这个数(原码)是多少了

补码反码原码十进制数
1111 11110000 00001111 1111232 -1

最终计算机得到的是一个非常大的数,232 -1,所以a+b的值远远大于0,程序输出了a+b>0的结果。

232 -1转换成16进制刚好就是0xFFFFFFFF,和计算机输出的16进制结果一样,至于最后为什么输出的是-1,原因是用%d输出的时候要再把它转换成int,也就是无符号整型转回原来的有符号整型。

0xFFFFFFFF-0x0000 0001=0xFFFFFFFE
符号位不变,取反之后得到原码:1000 0000 0000 0000 0000 0000 0000 0001,转换成十进制就是-1啦。

折腾了一下午,以上只是我个人的理解,如果有错的地方,还请指出!

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值