0%

关于原码、反码及补码的一些总结

大小端字节序

小端:数字的低位存到内存的低地址上。
大端:数字的低位存到内存的高地址上。
_大端字节序符合平时直觉,一台机器大端还是小端,取决于CPU_

int a = 0x11223344

低地址 0x100 0x101 0x102 0x103 高地址
低地址 44 33 22 11 小端
低地址 11 22 33 44 大端

原码反码与补码

例如-10:
1000 0000 0000 0000 0000 0000 0000 1010 原码
1111 1111 1111 1111 1111 1111 1111 0101反码
1111 1111 1111 1111 1111 1111 1111 0110补码(原码取反再加一,得到补码)

计算机采用补码来存储,肯定要比直接用原码麻烦,付出这样的代价是为了让计算机的硬件 设备实现起来更简单,通过补码的方式,能够把二进制的加减法统一成加法运算
例如:
计算 0 - 1 => 0 + (-1)
1000 0000 0000 0000 0000 0000 0000 0001 -1的原码
1111 1111 1111 1111 1111 1111 1111 1110 ,-1的反码
1111 1111 1111 1111 1111 1111 1111 1111 , -1的补码
计算 2-1 2+(-1)
1111 1111 1111 1111 1111 1111 1111 1111 ,-1的补码
1000 0000 0000 0000 0000 0000 0000 0010 ,2的补码(正数的原码反码补码都一样)
「对于负数来说,需要把原码转成补码在储存,也需要用到补码转原码」
「原码转补码是 取反+1」
「补码转原码还是 取反+1」

关于char类型的一些问题

char 一个字节的变量,当按照\%d打印的时候,就会把char隐式转换成int类型的变量,再打印

1000 0001 -1的原码
1111 1110 -1的反码
1111 1111 -1的补码
\%d打印的时候就先将a先隐式转换成int
这个转换过程中,高位的三个字节也要填充,按照符号为来填充(如果a的符号位是0,高位就补0;反之补1)
此时
char => int
1111 1111 => 1111 1111 1111 1111 1111 1111 1111 1111 => -1的补码
高位补1也就是为了防止出现这样转换过程中出现数据错误的情况

1111 1111 -1在内存中的存储 unsigned char 存的还是八个1,此时最高位的1 不再是符号位了,八个1理解成正数(不考虑符号位)的结果就是255,\%d打印时,1111 1111 => 高位补0(unsigned char没有符号位)
0000 0000 0000 0000 0000 0000 1111 1111

char的范围:-128 => +127
128 转化成二进制

1000 0000 0000 0000 0000 0000 1000 0000 -128原码
1111 1111 1111 1111 1111 1111 0111 1111 -128反码
1111 1111 1111 1111 1111 1111 1000 0000 -128补码

Char a = -128
1000 0000
👇
1111 1111 1111 1111 1111 1111 1000 0000(int)
👇
1111 1111 1111 1111 1111 1111 1000 0000(unsigned int)
此时最高位不再是符号位,不再表示负数,被理解成了一个很大的数字

128 内存中的二进制表示方式
0000 0000 0000 0000 0000 0000 1000 0000 (int)
Char a =128;
1000 0000
发生了截断
导致唯一的一个1阴差阳错的成了符号位,此时a的本质上是-128

-------------本文结束感谢您的阅读-------------