是什么

  • 定义:在计算机底层,无论有符号数还是无符号数,加减法统一使用补码并在同一个加法器(ALU)中进行。数据类型的转换(如 intunsigned int 的互相赋值)仅仅改变编译器对底层二进制序列的解释方式,绝不改变二进制序列本身

  • 大白话:CPU是个“没有感情的做题机器”,它不认识十进制,也不区分正负数。它只知道把你给的数字变成 0 和 1 的补码,然后像小学生列竖式一样加起来。至于算出来的结果是几,全看你(数据类型)怎么解读这串 0 和 1。

核心内容

1. 运算的黄金法则

  • 绝对不要直接用十进制去算底层寄存器的内容!

  • 第一步永远是:把十进制转换为底层的 二进制补码(或十六进制),在底层做完加减法、截断后,再根据变量类型翻译回十进制。

2. 无符号数(unsigned)的计算

  • 原码、反码、补码完全相同。

  • 解释方式:所有位都是数值位。8位字长范围:

  • 例:

3. 有符号数(int)与负数的补码表示

  • 解释方式:最高位是符号位(0为正,1为负),剩余位是数值位。8位字长范围:

  • 负数求补码公式原码除符号位外,各位取反,末位加1

    (大白话:把正数的二进制全部反过来,再加1)

  • 从负数补码求回真值(绝对值):同样是 各位取反,末位加1

4. 底层加减法怎么算

  • 加法 直接在底层做补码加法。

  • 减法 转换为补码加法

  • 截断规则:如果相加后超出字长(如 8 位机器算了 9 位出来),直接丢弃最高位的进位,只保留低 8 位

例题

  • 题目:假定在一个8位字长的计算机中运行如下C程序段:

C

unsigned int x = 134;
unsigned int y = 246;
int m = x;
int n = y;
int k1 = m - n;

求变量 在底层寄存器中的十六进制内容,以及 的十进制真值。

  • 分析

    不能直接用十进制算 就完事了!必须走底层二进制,确认截断和补码转换的过程,否则稍微换个数字就会掉进溢出的坑里。

  • 答案

  1. 转二进制

  2. 类型转换m = x, n = y。因为底层的二进制没有任何改变,所以 存的还是 存的还是

  3. 底层减法变加法

  4. 算负数补码 的补码 = 按位取反加1 = (1111 0110) 取反 0000 1001,加1 0000 1010 =

  5. 相加得寄存器结果 底层 = (二进制 1001 0000)。

  6. 翻译回十进制 声明为 int,最高位是 1,代表负数。对其求绝对值(取反加1):0110 1111 + 1 = 0111 0000 = 。因为是负数,所以真值为

溢出判断机制及发生溢出的语句

判断方法:计算机内部通常通过判断符号位的进位情况来检测有符号数的溢出。

常见方法有(任写一种即可得分):

  • 双符号位法:运算结果的两个符号位如果不相同,则发生溢出(01正溢出,10负溢出)。

  • 进位异或法:设最高有效位(数值位)向符号位的进位为 ,符号位产生的进位为 。若 ,则发生溢出。

  • 符号逻辑法:若两个正数相加结果符号位为1,或两个负数相加结果符号位为0,则发生溢出。 能否利用同一个加法器辅助电路实现及理由 能。 理由:在计算机中,有符号整数和无符号整数均采用补码表示。不管是无符号数还是有符号数,其加减法运算在底层的位级操作是完全相同的。减法运算也会被转换为加上减数的负数补码的形式(即按位取反加1)。因此,这四种运算都可以通过同一个加法器(ALU)完成,只需在加法器的基础上增加控制逻辑处理进位和符号位即可。

⚠️ 易错点

Warning

  • 最容易搞错的点:直接用十进制代入计算 正确做法: 先转成二进制补码,在二进制层面算完并截断后,再根据类型(有符号/无符号)把二进制翻译回十进制。

  • 赋值改变数值的错觉 unsigned 赋值给 int,底层二进制绝对不变,只是最高位从“数值”变成了“符号”。

  • 无符号数没有“溢出(Overflow)” 无符号数加法超出字长叫进位(Carry)。溢出这个词在计算机组成原理中,特指有符号数相加/减时超出了表示范围(例如两个正数相加,符号位却变成了1)。