负数强转unsigned类型

11 篇文章 0 订阅

环境:

操作系统:Ubuntu 18.04.3 LTS

架构:Aarch64

内核:Linux 4.4.167

机器型号:RK3399

CMake:3.10.2

GCC:Ubuntu/Linaro 7.5.0-3ubuntu1~18.04

G++:Ubuntu/Linaro 7.5.0-3ubuntu1~18.04

GDB:GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git

Make:GNU Make 4.1

前言:好久没写博客了,最近临近年关突然看到一个有趣的话题,如果把一个负数强转成无符号型会发生什么呢?计算机是怎么处理的,这里我们基于arm64和x86_64结构进行分析,其他平台请自行测试,结果或有不同。

在此之前你需要明白一个概念,计算机是怎么表示负数的?和正数的表示方式有什么差别?

在计算机中,
正数是直接用原码表示的,如整数42(32bit),在计算机中就表示为:0000 0000 0000 0000 0000 0000 0010 1010。
负数以其正值的补码形式表示,如整数-42,在计算机中表示为:       1111 1111 1111 1111 1111 1111 1101 0110。

要搞懂这些,首先要弄明白几个重要概念:原码、反码和补码。

原码
一个正数的原码,是按照绝对值大小转换成的二进制数;
一个负数的原码,是按照绝对值大小转换成的二进制数,然后最高位补1。

比如 :
0000 0000 0000 0000 0000 0000 0010 1010是 42的 原码。
1000 0000 0000 0000 0000 0000 0010 1010是 -42的 原码。

反码
正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。

取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)

比如:
正数0000 0000 0000 0000 0000 0000 0010 1010的反码还是0000 0000 0000 0000 0000 0000 0010 1010
负数1000 0000 0000 0000 0000 0000 0010 1010每一位取反(除符号位),得1111 1111 1111 1111 1111 1111 1101 0101。

所以:1111 1111 1111 1111 1111 1111 1101 0101是 1000 0000 0000 0000 0000 0000 0010 1010的反码。

补码
正数的补码与原码相同;
负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1.

所以:1000 0000 0000 0000 0000 0000 0010 1010的补码为1111 1111 1111 1111 1111 1111 1101 0110

这个补码放到win10自带的程序员计算器就是-42,1111 1111 1111 1111 1111 1111 1101 0110就是-42计算机在内存里的二进制。

正文:说完了负数我们来说一说一开始的疑问,如果把负数强转成无符号数那么它的值该怎么计算呢?

这个很简单我们知道UINT32_MAX的值是4294967295,也就是1111 1111 1111 1111 1111 1111 1111 1111 1111,这个时候就没有符号位了,所有的数字参与运算,也就是

2^31+2^30+.....+2^0 = 4294967295,实际上(unsigned)-42的二进制就是-42的二进制,只不过没有符号位了。把1111 1111 1111 1111 1111 1111 1101 0110所有的值按照正数的方法相加

也就是:2^31+2^30+.....+2^0 - 2^5 - 2^3 -2^0 = 4294967295 - 41 = 4294967254

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值