有符号数和无符号数之间的转换(2020)C

有符号数和无符号数之间的转换

各位小伙伴咱们先从一个简单的例子demo1.c入手:

#include <stdio.h>
int main()
{
    if (0 > -1)
    {
        printf("AAA\n");
    }
    else
    {
        printf("BBB\n");
    }
    return 0;
}

不言而喻,这个程序的运行结果为:
AAA

因为程序上来就是一个if判断语句,如果 0 > − 1 0 > -1 0>1为真,则打印输出AAA,反之,则打印输出BBB。故输出了AAA
那我们继续再看,如果在0的后面加上一个udemo2.c结果会如何?嗯哼?

#include <stdio.h>
int main()
{
    if (0u > -1)
    {
        printf("AAA\n");
    }
    else
    {
        printf("BBB\n");
    }
    return 0;
}

程序运行结果为:
BBB
下面咱们来简单探讨一下,大家都知道demo1.c 0 与 1 0与1 01都是默认int类型。对于64位机器上int为4bytes,即32bit有符号,再加上绝大多数的机器内部是以补码的形式存储的;所以我们把int型的0、1的32位形式补码表示出来:
0 ->[0000 0000 0000 0000 0000 0000 0000 0000]
-1->[1111 1111 1111 1111 1111 1111 1111 1111]
对于demo2.c的程序是在demo1.c的基础之上在0后面加上一个u。故把0隐式转换为unsigned int,这是无符号int版本。那到底为什么结果就输出了BBB呢?这个又有什么影响呢?
原来C语言是这样规定的:对于大多数C语言的实现,处理同样的字长的有符号数和无符号数之间相互转换的一般规则是:数值可能会改变,但是位模式不变。大概意思就是,现在的demo2.c的条件判断0u > -1就是unsigned int 0 > [signed] int -1。所以需要一个类型向另外一个类型进行隐式转换。对于同样字长的有符号数和无符号数之间的隐式转换是有符号转向无符号数,当然,内部位上不会转变,只是改变读取位上的方式。所以把原先按照int类型读取-1的方式,改变为用unsigned int 的方式来读取其位上的0、1字符串序列:因为-1的位模式为[1111 1111 1111 1111 1111 1111 1111 1111],所以其转换为无符号的十进制表示即为:unsigned int的最大值 4294967295 4294967295 4294967295。所以程序中的条件判断语句0u > -1等价于0u > 4294967295。所以才会得出这个程序运行结果。当然我们也可以验证一下的:

#include <stdio.h>
int main()
{
    int x = -1;
    if (0 > x)
    {
        printf("AAA\n");
        printf("%d\n", x);
        printf("%u\n", x);
    }
    else
    {
        printf("BBB\n");

        printf("%d\n", x);
        printf("%u\n", x);
    }
    return 0;
}

程序运行结果:
AAA
-1
4294967295
等价于demo1.c

#include <stdio.h>
int main()
{
    int x = -1;
    if (0u > x)
    {
        printf("AAA\n");
        printf("%d\n", x);
        printf("%u\n", x);
    }
    else
    {
        printf("BBB\n");

        printf("%d\n", x);
        printf("%u\n", x);
    }
    return 0;
}

程序运行结果:
BBB
-1
4294967295
等价于
demo2.c
这里再次验证了结论,就是数值可能会改变,但是位模式不变

C语言允许在各种不同的数字数据类型之间做强制类型转换。例如,假设变量x声明为int,u声明为unsigned。表达式(unsigned)x会将x的值转换成一个无符号数值,而(int)u将u的值转换成一个有符号整数。将有符号数强制类型转换成无符号数,或者反过来,会得到什么结果?从数学的角度来说,可以想象到几种不同的规则。很明显,对于在两种形式中都能表示的值,我们是想要保持不变的。另外一个方面,将负数转换成无符号数可能会得到0.如果转换的无符号数太大以至于超过了补码能够表示的范围,可能会得到该范围的最大值。不过,对于C语言的实现来说,对这个问题的回答都是从位级角度来看,而不是从数的角度
在这里插入图片描述

比如说,考虑下面的代码:

short int v = -12345;
unsigned short uv = (unsigned short)v;
printf("v = %d, uv = %u\n",v,uv);

在一台采用补码的机器来说,上述代码会产生如下输出:
v = -12345, uv = 53191
原因如下:
首先对于有符号整型v来说,-12345在采用补码的机器上面存储的位模式为[1100 1111 1100 0111]
其次对于无符号整型uv来说,53191在采用补码的机器上面存储的位模式位[1100 1111 1100 0111]
在这里插入图片描述

还可以反过来检验:

/**十六进制表示写作0xcfc7的16位位模式既是-12345的补码表示,又是53191的无符号表示。同时注意:12345+53191 = 65536 = 2^16这个属性可以推广到给定位模式的两个数值(补码和无符号数)之间的关系。*/
#include <stdio.h>
int main()
{
    unsigned short x = 0xcfc7;
    short y = 0xcfc7;
    printf("%u\n", x);
    printf("%d\n", y);
    return 0;
}

程序输出示例:

53191
-12345

综上,***强制类型转换的结果保持位值不变,只是改变了解释这些位的方式***。因为由上图可知,-12345的16位补码表示与53191的16位无符号表示是完全一致的。将short强制类型转换为unsigned short改变数值[解释这些位的方式],但是不改变位表示本身
对于大多数C语言的实现,处理同样的字长的有符号数和无符号数之间相互转换的一般规则是:数值可能会改变,但是位模式不变

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ocodotial

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值