C语言系列之——(4)原码、反码、补码
原码,反码,补码
- 1.二进制和进制转换
- 1.1 什么是进制
- 1.2 进制间的转换
- a.十进制转二进制
- b.二进制转八进制
- c.二进制转十六进制
- 2.原码、反码、补码
- 2.1 前置知识准备
- a.这三个码是什么
- b. 不同整数三码的区别
- b.1 负数与非负数之间
- b.2 signed和unsigned之间
- b.2.1 计算机存储单位说明
- b.2.2 signed和unsigned之间三码的区别
- 2.2 整数与三码间的转换
- a.整数->原码
- b.原码->反码
- c.反码->补码
- d.补码->反码->原码
- 2.3 整数在内存中的存储与补码运算
- a. 先上结论
- b. 为什么一定要用补码存储整数
- c. 补码运算
1.二进制和进制转换
1.1 什么是进制
我们常常听到二进制、八进制、十进制、十六进制这样的说法,这些是什么意思呢
其实,它们只是数值的不同表现形式
每种进制下,从右往左分别是个位,十位,百位……只是不同进制下每一位的权重是不一样的
不同进制下从右往左每一位的权重如下
二进制:2 0 2^020,2 1 2^121,2 2 2^222……
八进制:8 0 8^080,8 1 8^181,8 2 8^282……
十进制:10 0 10^0100,10 1 10^1101,10 2 10^2102……
十六进制:16 0 16^0160,16 1 16^1161,16 2 16^2162……
每一位上的数字在等于其进制数时会往下一位进一位,自己这一位变为0
(如10进制下每一位上的数最大只能是9,当某一位上数变为10时,会向其左边的第一位进1,自己变成0,所以9+1=10,79+1=80,78+30=108)
(十六进制下为表示每一位上大于9的数,用字母A代表10,B表示11,以次类推,一直到F表示15)
对应进制下表示的数字等于其每一位上的数字和对应权重之积的和
**以十五这个数在不同进制下的表示为例:
二进制:1111(15 = 1x2 0 2^020+ 1x2 1 2^121+1x2 2 2^222+1x2 3 2^323= 1 + 2 + 4 + 8 )
八进制:17
十进制:15
十六进制:F
1.2 进制间的转换
a.十进制转二进制
十进制转二进制最简方法为:短除法,其规则可以总结为8个字:除 2 取余,逆序排列
以8转二进制为例:
8 ÷ 2 = 4(余0)
4 ÷ 2 = 2(余0)
2 ÷ 2 = 1(余0)
1 ÷ 2 = 0(余1)
最后余数序列0001逆序排列为:1000
b.二进制转八进制
因为八进制下每一位的数字范围为0~7,刚好可以被三位二进制数覆盖(000 ~ 111),所以二进制转八进制的规则是:从二进制序列的右边低位开始,向左每3个二进制位按从右往左2 0 2^020,2 1 2^121,2 2 2^222的权重换算成一个八进制位,不足3位的直接换算
以1011转八进制为例:
1011从右往左三个三个可分为两段:011,1
从右往左依次换算成八进制位下数,011 -> 3,1 -> 1
得到的八进制数:13
c.二进制转十六进制
和转八进制类似,从二进制序列的右边低位开始,向左每4个二进制位按从右往左2 0 2^020,2 1 2^121,2 2 2^222,2 3 2^323的权重换算成一个十六进制位,不足4位的直接换算
(其他进制下每位数权重再各位求和即得十进制数)
2.原码、反码、补码
2.1 前置知识准备
a.这三个码是什么
整型数据 / 整数的二进制表示方法有三种:原码,反码,补码
(char类型变量中存的实际是字符对应地ASCLL码值,所以也是整型类型)
b. 不同整数三码的区别
b.1 负数与非负数之间
总结下来就是:
非负整数的原、反、补码三码相同,只要得到其中一个码就得到了所有三码;负整数的三码各不相同,需要分别计算转换
b.2 signed和unsigned之间
b.2.1 计算机存储单位说明
在计算机中,最小的存储单位是比特(bit),1个二进制位=1bit
接下来比比特大的单位为字节(Byte),1字节=8bit
再之后的存储单位关系如下:
1KB = 1024Byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
(这里对存储单位进行说明主要是想补充:一个二进制位=1bit 这个前置知识)
b.2.2 signed和unsigned之间三码的区别
signed
1.有符号整数二进制的这三种表示方法下,二进制序列都有符号位和数值位之分
2.最高位的1位(即所有比特位中最左边那位)叫做符号位,其余位叫做数值位
3.有符号整数的正负数之分体现在符号位上,而数字的绝对值大小体现在数值位上
4.符号位上为0表示“正”(当然0是不是正数也不是负数),为1表示“负”
(下面以int为例,因为int的大小为4字节,所以其二进制表示下可以分配到32个比特位)
unsigned
二进制序列没有符号位与数值位之分,全是数值位
正是因为符号位和数值位的差别:
同类型的unsigned整数能够表示的最大值为signed整数可表示的最大值的两倍+1
unsigned只可表示非负数,signed可表示负数,0,正数
2.2 整数与三码间的转换
(因为非负整数三码相同,所以下面的原码->反码->补码只针对负整数而言)
a.整数->原码
直接将整数按照正负数的形式翻译成二进制得到的就是原码
inta=-10;-15的原码为:(为方便观看,下面把32个比特位以一个字节为单位每8个间隔开)10000000000000000000000000001010b.原码->反码
原码符号位不变(如果有的话),其他位依次按位取反就可以得到反码
(按位取反规则:二进制每一位,0变1,1变0)
inta=-10;-10的原码为:(为方便观看,下面把32个比特位以一个字节为单位每8个间隔开)10000000000000000000000000001010-10的反码为:11111111111111111111111111110101c.反码->补码
反码+1就得到补码(每一位逢2进1变0,若进位后总位数多出正确位数,则舍去多出的位数)
inta=-10;-10的原码为:(为方便观看,下面把32个比特位以一个字节为单位每8个间隔开)10000000000000000000000000001010-10的反码为:11111111111111111111111111110101-10的补码为:11111111111111111111111111110110若反码为:11111111111111111111111111111111其转补码+1得100000000000000000000000000000000,比正确的32位多1位,则舍去多出来的那一位1,得补码:00000000000000000000000000000000d.补码->反码->原码
将上诉的三种转换倒过来执行即可
2.3 整数在内存中的存储与补码运算
a. 先上结论
计算机只认识二进制0和1,而整数实际是以补码的形式存储在内存中的,所以,所有的整数运算,都是用补码进行计算的
原码和反码只是人们用来计算补码的工具,内存中并不存在
b. 为什么一定要用补码存储整数
这是因为不用补码有两个硬伤:
1.原码和反码表示下,0都有两种表示形式
-0和+0都是同一个数0但是:(原码)-0->10000000000000000000000000000000+0->00000000000000000000000000000000(反码)-0->11111111111111111111111111111111+0->00000000000000000000000000000000这两种表现方式下,同一个数0都占了两个不同的编码,使得可表示的数少了一个,空间直接浪费了一个 而且还会导致运算逻辑混乱 而补码则能完美解决这个问题:+0=-0->000000000000000000000000000000002.若不用补码存储整数,减法运算无法直接用加法实现,硬件成本高
计算机的 CPU 里,天生只有加法器,没有专门的减法器。如果用原码做减法,比如 5 - 3,就需要额外的电路来处理符号位、比较绝对值大小,再做减法,这会让硬件变得非常复杂,成本飙升。
而用补码存储整数进行减法运算,可以自动将减法运算变为加法运算,且结果正确
以5-3为例 补码下,5-3->5的补码+(-3的补码)5的补码:00000000000000000000000000000101-3的补码:111111111111111111111111111111015+(-3):100000000000000000000000000000010->舍去多的一位->0000000000000000000000000000001000000000000000000000000000000010恰好就是2的补码,5-3=2c. 补码运算
上面已经说过,所有的整数运算,都是用补码进行计算的
那有哪些整数运算呢?
算数运算
常用的算术运算有 + , - , * , / , %
(因为除±外其他都涉及一些位运算规则,所以这里先不进行讲解,等到讲操作符时就会将其他的这些运算补齐)
(在上面讲用补码存储的第二个原因的例子中已体现±运算,所以不再赘述)
注意:一些不同类型的整型变量在进行算数运算时,会发生整型提升或算术转换,此时运算的过程就更复杂些,上面举的例子是同类型整型变量间的运算规则,至于整型提升与算术转换的场景,将在后续文章中解释~
(下面这些运算同样会在讲解操作符时补齐)
位运算:~,&,|,^,<<,>>
复合赋值运算:+=,-=,……
比较运算,±号
