• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

progressive_bird

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

C语言系列之——(4)原码、反码、补码

目录
  • 1.二进制和进制转换
    • 1.1 什么是进制
    • 1.2 进制间的转换
      • a.十进制数转非十进制数
        • 示例:十进制转二进制
      • b.2K进制间转换
        • 示例:二进制转8进制
        • 示例:十六进制转8进制
  • 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 什么是进制

我们常常听到 二进制、八进制、十进制、十六进制 这样的说法,这些是什么意思呢
其实,它们只是数值的不同表现形式

每种进制下,整数部分从右往左分别是个位、十位、百位…… 只是不同进制下每一位的权重不一样

不同进制下整数部分从右往左每一位的权重如下

  • 二进制:20,21,22……
  • 八进制:80,81,82……
  • 十进制:100,101,102……
  • 十六进制:160,161,162……

小数部分,小数点右侧,权重是进制的负幂次,从左往右依次:

  • 二进制小数:2-1,2-2,2-3……
  • 八进制小数:8-1,8-2,8-3……
  • 十进制小数:10-1,10-2,10-3……
  • 十六进制小数:16-1,16-2,16-3……

每一位上的数字在等于其进制数时会往下一位进一位,自己这一位变为0
(如10进制下每一位上的数最大只能是9,当某一位上数变为10时,会向其左边的第一位进1,自己变成0,所以9+1=10,79+1=80,78+30=108)
(十六进制下为表示每一位上大于9的数,用字母A代表10,B表示11,以次类推,一直到F表示15)

对应进制下表示的数字等于其每一位上的数字和对应权重之积的和

整数示例:15 在不同进制

  • 二进制:11112 = 1×20 + 1×21 + 1×22 + 1×23 = 1 + 2 + 4 + 8 = 1510
  • 八进制:178 = 7×80 + 1×81 = 1510
  • 十进制:1510
  • 十六进制:F16 = 15×160 = 1510

小数示例:二进制 0.1012 转十进制
0.1012 = 1×2-1+0×2-2+1×2-3=0.5+0+0.125=0.62510


1.2 进制间的转换

a.十进制数转非十进制数

整数部分:基除法(除基取余,逆序排列)

将整数部分除以基数 r,所得的商作为被除数继续除以基数 r,反复进行这个过程,直到商为 0;
保留每一步的余数,从最后一个余数读到第一个余数,最后一个余数为最高有效位,第一个余数为最低有效位,得到非十进制整数。

小数部分:基乘法(乘基取整,顺序排列)

对给定的小数乘以基数 r,所得乘积保留整数部分,小数部分再乘以基数 r,反复进行这个过程,直到乘积的小数部分为 0,或者达到要求的精度时停止;
保留每一步取出的整数,从第一个整数读到最后一个整数,从左到右排列,得到非十进制小数。

如果 “基乘” 法不能使小数部分收敛为 0,说明这个小数无法用该非十进制数精确表达,精度由保留的数字位数决定。

示例:十进制转二进制

整数部分:除2取余,逆序排列

8转二进制:
8 ÷ 2 = 4(余0)
4 ÷ 2 = 2(余0)
2 ÷ 2 = 1(余0)
1 ÷ 2 = 0(余1)
最后余数序列0001逆序排列为:1000

小数部分:乘 2 取整,顺序排列
十进制小数不断乘以 2,取出每次计算得到的整数部分;
剩下新的小数继续乘 2,直到小数部分等于 0(部分小数无法归零,表示该10进制数无法被2进制精确表示,按需保留精度)
取出的整数按顺序排列就是二进制小数

十进制 0.62510 转二进制:
(0.625 × 2 = 1.25) 取出整数:1,剩余小数 (0.25)
(0.25 × 2 = 0.5) 取出整数:0,剩余小数 (0.5)
(0.5 × 2 = 1.0) 取出整数:1,剩余小数 (0.0),结束
整数依次顺序:1 0 1 → 二进制小数 0.1012

b.2K进制间转换

  • 对于 2K 进制数,每位都可转换为 K 位的二进制数
    (如八进制的每个数字都可以用 3 位二进制数表示,0~7,000 ~111 ; 十六进制的每个数字都可以用 4 位二进制数表示,0~F,0000 ~ 1111)

  • 二进制数也可以转换为 2K 进制数,每 K 位组成一组,转换为对应的 2K 进制的一个数字

  • 如果转换的两个数制的基都是 2 的幂次,可以先转换为二进制,然后再进行转换

示例:二进制转8进制

八进制下每一位的数字范围为0~7,刚好可以被三位二进制数覆盖(000 ~ 111)

规则:

  • 整数部分:从二进制低位(最右边)开始,向左每 3 位分组;最左侧不足 3 位,高位补 0
  • 小数部分:从小数点向右,每 3 位分组;最右侧不足 3 位,低位补 0
    每组 3 位二进制换算成 1 位八进制

二进制 1011.112 转八进制
拆分:整数 1011 → 补0分组 001 011;小数 11 → 补0分组 110
001=1,011=3,110=6
结果:13.68

示例:十六进制转8进制

十六进制与八进制都是 2 的幂次进制,先把十六进制转为二进制,再将二进制转为八进制
十六进制 1 位对应 4 位二进制;八进制 1 位对应 3 位二进制

十六进制 2A.416 转八进制

  1. 十六进制每一位展开成 4 位二进制:
    216=0010,A16=1010,416=0100
    2A.416 = 0010 1010.01002
  2. 整理二进制,按八进制规则,整数向左每 3 位分组,小数向右每 3 位分组,不足补 0:
    整数部分:001010 → (001 010)
    小数部分:0100 → (010 0),低位补 0 得到 (010 000)
    完整分组:001 010 . 010 0002
  3. 每组 3 位二进制转 1 位八进制:
    001=1,010=2,010=2,000=0
    结果:12.28

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.整数->原码

直接将整数按照正负数的形式翻译成二进制得到的就是原码

int a = -10;
-15的原码为:(为方便观看,下面把32个比特位以一个字节为单位每8个间隔开)
10000000 00000000 00000000 00001010

b.原码->反码

原码符号位不变(如果有的话),其他位依次按位取反就可以得到反码

(按位取反规则:二进制每一位,0变1,1变0)

int a = -10;
-10的原码为:(为方便观看,下面把32个比特位以一个字节为单位每8个间隔开)
10000000 00000000 00000000 00001010
-10的反码为:
11111111 11111111 11111111 11110101

c.反码->补码

反码+1就得到补码(每一位逢2进1变0,若进位后总位数多出正确位数,则舍去多出的位数)

int a = -10;
-10的原码为:(为方便观看,下面把32个比特位以一个字节为单位每8个间隔开)
10000000 00000000 00000000 00001010
-10的反码为:
11111111 11111111 11111111 11110101
-10的补码为:
11111111 11111111 11111111 11110110

若反码为:
11111111 11111111 11111111 11111111
其转补码+1得1 00000000 00000000 00000000 00000000,比正确的32位多1位,则舍去多出来的那一位1,得补码:
00000000 00000000 00000000 00000000

d.补码->反码->原码

将上诉的三种转换倒过来执行即可


2.3 整数在内存中的存储与补码运算

a. 先上结论

计算机只认识二进制0和1,而整数实际是以补码的形式存储在内存中的,所以,所有的整数运算,都是用补码进行计算的
原码和反码只是人们用来计算补码的工具,内存中并不存在


b. 为什么一定要用补码存储整数

这是因为不用补码有两个硬伤:

1.原码和反码表示下,0都有两种表示形式

-0和+0都是同一个数0
但是:
(原码)                                    
-0 -> 10000000 00000000 00000000 00000000    
+0 -> 00000000 00000000 00000000 00000000
 (反码)
-0 -> 11111111 11111111 11111111 11111111    
+0 -> 00000000 00000000 00000000 00000000
 
这两种表现方式下,同一个数 0 都占了两个不同的编码,使得可表示的数少了一个,空间直接浪费了一个
而且还会导致运算逻辑混乱

而补码则能完美解决这个问题:
+0 = -0 -> 00000000 00000000 00000000 00000000

2.若不用补码存储整数,减法运算无法直接用加法实现,硬件成本高

计算机的 CPU 里,天生只有加法器,没有专门的减法器。如果用原码做减法,比如 5 - 3,就需要额外的电路来处理符号位、比较绝对值大小,再做减法,这会让硬件变得非常复杂,成本飙升。

而用补码存储整数进行减法运算,可以自动将减法运算变为加法运算,且结果正确

以 5 - 3 为例
补码下,5 - 3 -> 5的补码 + (-3的补码)

 5的补码:00000000 00000000 00000000 00000101
-3的补码:11111111 11111111 11111111 11111101
 5+(-3):1 00000000 00000000 00000000 00000010 ->舍去多的一位-> 00000000 00000000 00000000 00000010
 
 00000000 00000000 00000000 00000010 恰好就是2的补码,5-3=2

c. 补码运算

上面已经说过,所有的整数运算,都是用补码进行计算的

那有哪些整数运算呢?

算数运算
常用的算术运算有 + , - , * , / , %
(因为除+-外其他都涉及一些位运算规则,所以这里先不进行讲解,等到讲操作符时就会将其他的这些运算补齐,并且说明进行补码运算时的 溢出 问题)

将操作符的文章在这里~

(在上面讲用补码存储的第二个原因的例子中已体现+-运算,所以不再赘述)

注意:一些不同类型的整型变量在进行算数运算时,会发生整型提升或算术转换,此时运算的过程就更复杂些,上面举的例子是同类型整型变量间的运算规则,至于整型提升与算术转换的场景,将在后续文章中解释~

(下面这些运算同样会在讲解操作符时补齐)
位运算:~,&,|,^,<<,>>
复合赋值运算:+=,-=,……
比较运算,+-号

posted on 2026-10-27 16:27  progressive_bird  阅读(7)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3