环境:
操作系统: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结构进行分析,其他平台请自行测试,结果或有不同。
在此之前你需要明白一个概念,计算机是怎么表示负数的正数的表示方式有什么差别/p>
在计算机中,
正数是直接用原码表示的,如整数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计算机在内存里的二进制。
正文:说完了负数我们来说一说一开始的疑问,如果把负数强转成无符 数那么它的值该怎么计算呢/strong>
这个很简单我们知道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
文章知识点与官方知识档案匹配,可进一步学习相关知识C技能树首页概览114812 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!