
答案先汇总如下:
| 题号 | 答案 |
|---|---|
| 03 | 0101 0100,按选项选对应这一项 |
| 04 | D,C0H |
| 05 | D,1100 1010 |
| 06 | C,CB8H |
| 07 | C,74H, DDH |
| 08 | C |
| 09 | A |
| 10 | C,r₁ × r₂ |
| 11 | B |
| 12 | B,01 |
| 13 | C0 ⊕ C1 = 1,即二者一个有进位、一个无进位时溢出 |
下面逐题讲。
03 题:补码定点整数算术左移两位
题目是:
0101 0101 算术左移两位。
补码的算术左移,在位形操作上可以按“整体左移,低位补 0”处理。也就是:
0101 0101 左移 1 位 -> 1010 1010
1010 1010 左移 1 位 -> 0101 0100
所以寄存器中的结果位形是:
0101 0100
但这里要注意一个考研易错点:0101 0101 是正数,十进制为 85。左移两位本质上相当于乘以 4,应得到 340,而 8 位补码整数范围是:
-128 ~ +127
所以数学结果已经超出范围。也就是说,题目若只问“左移后的机器位形”,结果是 0101 0100;若问“是否溢出”,则发生溢出。
04 题:算术左移不会发生溢出的是哪一个
判断补码左移一位是否溢出,最快方法是看左移前最高两位是否相同。
对于 8 位补码:
若符号位和最高数值位相同,左移一位不溢出;
若符号位和最高数值位不同,左移一位溢出。
逐个看:
80H = 1000 0000,最高两位是 10,溢出
90H = 1001 0000,最高两位是 10,溢出
B0H = 1011 0000,最高两位是 10,溢出
C0H = 1100 0000,最高两位是 11,不溢出
所以答案是:
D. C0H
这类题不要先转十进制,直接看最高两位最快。
05 题:补码定点整数右移一位
题目是:
1001 0101 右移一位
补码算术右移的规则是:高位补符号位,低位移出。
原数最高位是 1,说明是负数,所以右移时左边补 1:
1001 0101
右移一位
1100 1010
所以答案是:
D. 1100 1010
补码右移题的关键是:不是左边补 0,而是补符号位。
06 题:两个十六进制机器数相加
题目是:
7E5H + 4D3H
直接按十六进制加法算:
7 E 5
+ 4 D 3
-----------
C B 8
具体过程:
5 + 3 = 8
E + D = 14 + 13 = 27
27 = 1B,所以本位写 B,向高位进 1
7 + 4 + 1 = C
所以结果是:
CB8H
答案是:
C
07 题:BAH 的算术左移和算术右移
题目给出机器数字长为 8 位,机器数 BAH 为补码。
先把 BAH 转成二进制:
B = 1011
A = 1010
BAH = 1011 1010
算术左移 1 位:整体左移,低位补 0:
1011 1010 左移 1 位 -> 0111 0100
0111 0100 转十六进制:
0111 = 7
0100 = 4
所以是 74H
算术右移 1 位:高位补符号位。原数符号位是 1,所以左边补 1:
1011 1010 右移 1 位 -> 1101 1101
1101 1101 转十六进制:
1101 = D
1101 = D
所以是 DDH
所以答案是:
74H, DDH
选:
C
这里也有一个易错点:BAH 是负数,左移后变成了 74H,符号变了,所以这个左移结果实际上已经溢出。但题目问的是“移位后分别得什么位形”,所以仍按机器移位结果选 74H, DDH。
08 题:定点运算器中必须有什么电路
题目问:无论采用双符号位还是单符号位,必须有什么?
答案是:
溢出判断电路
单符号位补码加减法可以用进位关系判断溢出;双符号位补码可以用两个符号位是否相同判断溢出。这些判断本质上常用异或逻辑实现。
所以答案是:
C. 溢出判断电路,它一般用“异或”门来实现
09 题:机器运算产生溢出的根本原因
溢出的根本原因不是“符号位进位丢弃”,也不是“运算发生错误”,而是:
机器字长有限,能表示的数值范围有限。
例如 8 位补码只能表示:
-128 ~ +127
如果实际数学结果超过这个范围,就会溢出。
所以答案是:
A. 寄存器的位数有限
10 题:判断哪个运算会溢出
题目给出:
r₁ = F5H
r₂ = EEH
都是 8 位补码。
先转成十进制。
F5H 是负数,因为最高位为 1。可以用“无符号值 – 256”:
F5H = 245
245 - 256 = -11
所以 r₁ = -11
EEH:
EEH = 238
238 - 256 = -18
所以 r₂ = -18
8 位补码范围是:
-128 ~ +127
逐项判断:
A. r₁ + r₂ = -11 + (-18) = -29,不溢出
B. r₁ - r₂ = -11 - (-18) = 7,不溢出
C. r₁ × r₂ = (-11) × (-18) = 198,超过 +127,溢出
D. r₁ / r₂ = (-11) / (-18),结果不可能超出 8 位补码范围
所以答案是:
C. r₁ × r₂
这种题的关键是先把十六进制补码转成真值,再看结果是否超出表示范围。
11 题:关于模 4 补码
模 4 补码也叫变形补码,常见特点是使用双符号位来判断溢出。
合法的双符号位状态是:
00:正数
11:负数
发生溢出时:
01:正溢出
10:负溢出
但存储时不一定真的保存两个符号位。因为没有溢出时,两个符号位必然相同,所以存储每个模 4 补码时只需要保存一个符号位;进入运算器运算时再扩展成双符号位即可。
所以正确说法是:
B. 每个模 4 补码存储时只需要一个符号位
易错点在于:模 4 补码“运算时用双符号位”,但“存储时只需一个符号位”。不要把这两个场景混在一起。
12 题:双符号位下两个正数相加溢出的特征
双符号位补码中:
00 表示正数
11 表示负数
01 表示正溢出
10 表示负溢出
两个正数相加,如果发生溢出,一定是结果太大,超过最大正数范围,因此是正溢出。
正溢出的双符号位特征是:
01
所以答案是:
B. 01
13 题:用进位判断加减法溢出
题目说:
符号位的进位为 C0
最高位的进位为 C1
这里的考点是补码加减法溢出的进位判断法。
结论是:
C0 和 C1 不同,则溢出;
C0 和 C1 相同,则不溢出。
也就是:
C0 ⊕ C1 = 1 时溢出
具体说:
C0 = 1,C1 = 0,溢出
C0 = 0,C1 = 1,溢出
C0 = 1,C1 = 1,不溢出
C0 = 0,C1 = 0,不溢出
所以第 13 题不能简单理解成“有进位就溢出”。补码运算中,最高进位被丢弃是正常现象。真正判断溢出的标准是:
符号位进位和最高数值位进位是否不同。
因此本题答案应表述为:
C0、C1 一个产生进位,一个不产生进位。
也就是只满足 I 或只满足 II 的互斥情况;III 和 IV 都不溢出。

答案汇总:
| 题号 | 答案 |
|---|---|
| 16 | D,约 100 个周期 |
| 17 | D,I、II、III 都正确 |
| 18 | B,0100 0101, 1101 1001, 1 |
| 19 | A,1, 1 |
| 20 | C,DAH, 0 |
| 21 | A,8CH, 1 |
| 22 | A,CF, 王道 |
16 题:32 位无符号整数乘法需要多少周期
这题考的是最基本的“移位加法乘法器”。
对于 32 位无符号数乘法,通常要对乘数的 32 位逐位处理。每一轮大致包括:
判断乘数最低位
需要时进行一次加法
被乘数左移一位
乘数右移一位
题目说一次 ALU 运算和一次移位操作各需要 1 个时钟周期。按照基础乘法器模型,每轮约需要:
1 次 ALU 运算 + 2 次移位操作 = 3 个周期
一共 32 轮,所以:
32 × 3 = 96 个周期
由于题目问“约为”,所以选最接近的:
D. 100
这题容易错选 64。如果按“每轮一次加法 + 一次合并移位”理解,会得到 32 × 2 = 64。但本题选项中同时给出 96 和 100,并且问“约为”,明显是按基础移位加法乘法器的“三步法”理解,即约 100 个周期。
17 题:关于移位运算的判断
题目判断三个说法。
I:补码算术左移时,高位移出,低位补 0。若左移前后的符号位不同,则发生溢出。
这个说法正确。补码算术左移本质上相当于乘以 2。左移后如果符号位发生变化,说明结果超出补码可表示范围,发生溢出。
II:无符号数逻辑左移时,若最高位移出的是 1,则发生溢出。
这个说法也正确。无符号数左移相当于乘以 2,如果最高位移出的是 1,说明原来的高位有效信息被丢失,结果超过机器字长可表示范围。
III:逻辑左移和补码算术左移的结果都一样,都是移出最高位,并在低位补 0。
这个说法也正确。注意这里说的是“移位后的位形结果一样”。逻辑左移和补码算术左移在操作形式上都是:
高位移出,低位补 0
区别主要在于解释方式和溢出判断,而不是位移操作本身。
所以答案是:
D. I、II、III
18 题:用 8 位加法器计算无符号数 x – y
题目给出:
x = 69
y = 38
要求在 8 位加法器中计算 x - y,问两个输入端信息和低位进位信息分别是什么。
先把 x、y 转成 8 位二进制:
x = 69 = 0100 0101
y = 38 = 0010 0110
加法器本身只会做加法,要实现减法,一般用:
x - y = x + y 的按位取反 + 1
所以第二个输入端不是直接输入 y,而是输入 y 的按位取反:
y = 0010 0110
按位取反 = 1101 1001
低位进位输入为 1,用来完成“加 1”。
因此加法器输入应为:
第一个输入端:0100 0101
第二个输入端:1101 1001
低位进位:1
答案是:
B. 0100 0101, 1101 1001, 1
这里容易错选 1101 1010, 0。因为 1101 1010 是 -y 的补码形式,和 按位取反 + 1 的结果一样。但题目问的是“加法器的两个输入端信息和输入的低位进位信息”,标准减法器结构是第二输入端取反,低位进位置 1,所以应选 B。
19 题:补码表示下计算 x – y 的低位进位和 OF
题目给出:
[x]补 = F5H
[y]补 = 7EH
先把它们转成真值。
F5H 是 8 位补码,最高位为 1,是负数:
F5H = 245
245 - 256 = -11
所以 x = -11
7EH 最高位为 0,是正数:
7EH = 126
所以 y = 126
计算:
x - y = -11 - 126 = -137
8 位补码的表示范围是:
-128 ~ +127
-137 小于 -128,所以发生溢出,OF = 1。
再看低位进位输入。加法器计算减法时:
x - y = x + y 的按位取反 + 1
所以低位进位输入为:
1
因此答案是:
A. 1, 1
用机器数验证一下:
x = F5H = 1111 0101
y = 7EH = 0111 1110
~y = 81H = 1000 0001
Cin = 1
F5H + 81H + 1 = 177H
取低 8 位 = 77H
77H 是正数,但真实结果应是负数 -137,符号错误,说明确实溢出。
20 题:计算 x/2 + 2y 的机器数和 OF
题目给出:
[x]补 = 44H
[y]补 = DCH
先求真值。
44H = 0100 0100 = 68
DCH 最高位为 1,是负数:
DCH = 220
220 - 256 = -36
所以 y = -36
计算表达式:
x/2 + 2y
= 68/2 + 2 × (-36)
= 34 - 72
= -38
-38 在 8 位补码范围 -128 ~ +127 内,所以:
OF = 0
再把 -38 转为 8 位补码:
38 = 0010 0110
-38 的补码 = 1101 1010 = DAH
所以答案是:
C. DAH, 0
也可以直接用移位做:
x = 44H = 0100 0100
x/2:算术右移一位 -> 0010 0010 = 22H
y = DCH = 1101 1100
2y:算术左移一位 -> 1011 1000 = B8H
22H + B8H = DAH
结果为 DAH,且没有溢出。
21 题:计算 x – 2y 的机器数和 OF
题目仍然是:
[x]补 = 44H
[y]补 = DCH
由上一题可知:
x = 68
y = -36
2y = -72
所以:
x - 2y
= 68 - (-72)
= 140
但是 8 位补码范围是:
-128 ~ +127
140 超过最大正数 127,所以发生正溢出:
OF = 1
再看机器结果。先求 2y:
y = DCH = 1101 1100
2y = 算术左移一位 = 1011 1000 = B8H
计算:
x - 2y = 44H - B8H
用加法器实现减法:
44H - B8H = 44H + (~B8H) + 1
B8H = 1011 1000
~B8H = 0100 0111 = 47H
44H + 47H + 1 = 8CH
所以机器结果是:
8CH
但 8CH 最高位为 1,按补码解释是负数,这和真实数学结果 +140 不一致,说明发生溢出。
答案是:
A. 8CH, 1
22 题:C 语言代码中的比较使用哪个标志位,输出什么
代码是:
int si = 65536;
short i = si;
unsigned j = 0;
if (i <= j - 1)
printf("王道");
else
printf("计算机教育");
先看赋值:
si = 65536
short 通常是 16 位。65536 的十六进制是:
65536 = 0x00010000
赋给 16 位 short i 时,低 16 位为:
0000H
所以:
i = 0
再看:
unsigned j = 0;
所以:
j = 0
但是表达式中是:
i <= j - 1
由于 j 是 unsigned,所以 j - 1 按无符号数运算:
0 - 1 = 0xFFFFFFFF
也就是无符号整数的最大值。
同时,i 会被转换成无符号数参与比较:
i = 0
j - 1 = 0xFFFFFFFF
所以判断条件为真:
0 <= 0xFFFFFFFF
最终输出:
王道
因为这是无符号数比较,所以分支判断主要依据无符号比较相关的标志位,也就是 CF,而不是有符号溢出标志 OF。
答案是:
A. CF, 王道
这题的关键陷阱有两个:第一,short i = 65536 后 i 变成 0;第二,j 是 unsigned,所以 j - 1 不是 -1,而是无符号最大值。
在计算补码和反码的数字之和中,我们是不是要把它给进行化简到真数才比较方便计数,对吧?我们在判断是否溢出的时候,也可以利用算出来之后的数值来与范围进行比较,也可以利用,二进制求和之后首位来进行判断。在第22题里面,它这里面涉及到了大量的数据类型转换,不同数据类型进行比较,遵循的是什么规则?
对,可以把思路分成两层:一层是“为了算题方便,把机器数先译成真值”;另一层是“真正的机器运算,本质上仍然是按二进制位求和、取反、加 1、移位”。考研做题时,两种方法都要会,但使用场景不同。
一、补码、反码做加法时,要不要先转成真值?
如果题目只是问“这个运算是否溢出”“结果真值是多少”,先把补码、反码译成真值通常更直观。
例如 8 位补码:
F5H = 1111 0101
最高位是 1,说明是负数
真值 = 245 - 256 = -11
这种方法很适合快速判断:
x = -11
y = 126
x - y = -137
而 8 位补码范围是:
-128 ~ +127
所以 -137 溢出。
但是,如果题目问的是“机器结果是什么”“加法器输入端是什么”“OF、CF 是多少”,就不能只停留在真值层面,还要回到机器数按位运算。
比如计算补码减法:
x - y = x + (-y)
在加法器中通常实现为:
x + 按位取反(y) + 1
所以题目问加法器的输入端时,答案不是直接输入 -y 的真值,而是输入 y 的按位取反,并且低位进位 Cin = 1。
所以可以这样记:
判断数值大小、是否超范围:转真值最方便;
求机器结果、标志位、加法器输入:必须看二进制位运算。
二、补码加法溢出,不能只看结果最高位
你说“可以利用二进制求和之后首位来判断”,这里要稍微修正一下:只看结果最高位是不够的。
补码加法溢出的判断,常用两种方法。
第一种,真值范围判断法:
n 位补码范围:-2<sup>n-1</sup> ~ 2<sup>n-1</sup> - 1
例如 8 位补码范围:
-128 ~ +127
如果数学真值结果超出这个范围,就溢出。
第二种,符号位判断法:
同号相加,结果变号,则溢出;
异号相加,一定不溢出。
具体来说:
正数 + 正数 = 负数,正溢出
负数 + 负数 = 正数,负溢出
正数 + 负数,不溢出
负数 + 正数,不溢出
所以不能只看“结果最高位是 0 还是 1”。例如:
0100 0000 + 1100 0000 = 0000 0000
一个正数加一个负数,结果最高位是 0,但这不代表发生了溢出。因为异号相加本来就不会溢出。
第三种,进位判断法:
符号位的进位 C0
最高数值位向符号位的进位 C1
若 C0 ≠ C1,则溢出;
若 C0 = C1,则不溢出。
也就是:
OF = C0 ⊕ C1
这也是硬件中很常见的溢出判断方法。
三、反码加法和补码加法有什么区别?
补码加法最简单:
直接按二进制相加,最高位进位丢弃。
例如 8 位补码相加,如果产生第 9 位进位,直接舍弃即可。
但反码加法不同。反码加法有一个特殊规则:
最高位产生的进位,要循环加到最低位。
这叫“循环进位”或者“回卷进位”。
例如反码运算中,如果两个 8 位反码相加得到:
1 0010 1010
前面的最高进位 1 不能直接丢掉,而是要加回最低位:
0010 1010
+ 1
---------
0010 1011
所以反码加法题要特别注意:补码最高进位丢弃,反码最高进位循环加回最低位。
不过现在 408 中主要考补码,反码更多用于理解机器数表示和转换。真正做加减法、判断溢出时,补码是重点。
四、第 22 题涉及的 C 语言类型转换规则
第 22 题的核心不是机器数加减,而是 C 语言的“整型提升”和“通常算术转换”。
代码大致是:
int si = 65536;
short i = si;
unsigned j = 0;
if (i <= j - 1)
printf("王道");
else
printf("计算机教育");
这里有三层转换。
1. 赋值给 short 时发生截断
假设常见考研环境:
int 32 位
short 16 位
unsigned 32 位
si = 65536,也就是:
65536 = 0x00010000
赋给 16 位 short i 时,只保留低 16 位:
0x00010000 的低 16 位 = 0x0000
所以:
i = 0
严格按 C 标准,超出 short 表示范围的赋值结果与具体实现有关;但在 408 和常见机器题中,一般按“截取低位”处理。
2. j - 1 中,1 会转换成 unsigned
因为:
unsigned j = 0;
所以表达式:
j - 1
不是有符号运算,而是无符号运算。
1 会先转换成 unsigned int,于是:
j - 1 = 0u - 1u
无符号整数运算发生下溢时,不是得到 -1,而是按模运算回绕。
对于 32 位 unsigned:
0u - 1u = 2<sup>32</sup> - 1 = 0xFFFFFFFF
所以:
j - 1 = UINT_MAX
也就是无符号最大值。
3. i <= j - 1 比较时,i 也会转换成 unsigned
此时左边是:
i = 0
右边是:
j - 1 = 0xFFFFFFFF
因为右边是 unsigned int,所以比较时,左边的 i 也要转换成 unsigned int。
于是判断变成:
0u <= 0xFFFFFFFFu
这个条件成立。
所以最终输出:
王道
五、C 语言不同整数类型混合运算的基本规则
408 中常考的是下面这个顺序。
第一步,先做整型提升。
小于 int 的整数类型,例如:
char
short
signed char
unsigned char
unsigned short
在表达式运算前,通常会先提升为 int。如果 int 表示不了全部值,才提升为 unsigned int。
所以:
short i;
在参与表达式运算时,通常先变成 int。
第二步,如果两边类型不同,就做通常算术转换。
常见规则可以这样记:
有 double 向 double 转;
有 float 向 float / double 转;
整数之间,先看 signed / unsigned,再看等级 rank。
对于 408 常见整型题,重点是 signed 和 unsigned 的混合运算:
如果有 unsigned int,另一个 int 通常会转换成 unsigned int。
所以:
int a = -1;
unsigned b = 1;
a < b
不是比较:
-1 < 1
而是先把 a 转成 unsigned:
-1 转成 unsigned = 0xFFFFFFFF
于是变成:
0xFFFFFFFF < 1
结果是假。
这类题非常容易错,因为从数学直觉看 -1 < 1 是真,但 C 语言实际按无符号数比较,结果变成假。
六、第 22 题为什么用 CF,而不是 OF?
这题问“条件判断依据什么标志寄存器”,答案选 CF,因为最终比较是无符号比较。
要区分:
有符号数比较:主要看 SF、OF、ZF
无符号数比较:主要看 CF、ZF
其中:
CF:进位 / 借位标志,常用于无符号数比较
OF:溢出标志,常用于有符号数比较
ZF:零标志,用于判断是否相等
对于无符号比较:
a < b 看 CF = 1
a == b 看 ZF = 1
a <= b 看 CF = 1 或 ZF = 1
所以严格说,<= 这种判断不仅可能涉及 CF,也会涉及 ZF。但在选择题里,通常把“无符号比较”归结为看 CF,把“有符号比较”归结为看 OF 相关标志。
因此第 22 题选:
CF,王道
七、做这类题的固定流程
遇到 C 语言整数转换题,最好不要直接凭直觉比较,而是按下面顺序走:
1. 先看变量声明类型:int、short、unsigned、char 等;
2. 看赋值时是否发生截断;
3. 看表达式中是否有 unsigned;
4. 小整型先提升为 int;
5. signed 和 unsigned 混合时,通常转成 unsigned;
6. 最后再判断比较结果和输出。
第 22 题完整流程就是:
si = 65536 = 0x00010000
short i = si
=> i 取低 16 位
=> i = 0
unsigned j = 0
j - 1
=> 0u - 1u
=> 0xFFFFFFFFu
i <= j - 1
=> 0u <= 0xFFFFFFFFu
=> true
输出:王道
所以这道题真正考的是:C 语言中 unsigned 会“污染”整个表达式,使比较转为无符号比较。
在2021题里面,cah ,8ch我能知道它是否会溢出,但是我不知道,就是说它溢出的时候会输出什么样的结果,以及在第22题里面标志寄存器中的cf of这几个概念,其实我也不太理解,你能给我讲一下吗?
你这里问的是两个很关键的点:第一,补码运算发生溢出时,机器到底给出什么结果;第二,CF、OF 这些标志位到底表示什么,以及为什么第 22 题看 CF 而不是 OF。
先说结论:溢出时,机器仍然会输出一个固定字长的二进制结果,但这个结果已经不能当作正确的有符号真值来解释。
也就是说,寄存器不会因为溢出就“不输出”或者输出特殊符号,而是照样把低 8 位、低 16 位、低 32 位保留下来,同时把溢出标志 OF 置为 1,告诉后续电路或程序:“这个有符号结果不可信”。
一、补码溢出时,机器输出的是什么?
以第 21 题为例:
[x]补 = 44H
[y]补 = DCH
求 x - 2y 的机器数和 OF
先转真值:
44H = 0100 0100 = 68
DCH = 1101 1100
最高位为 1,是负数
真值 = 220 - 256 = -36
所以:
x = 68
y = -36
x - 2y = 68 - 2 × (-36)
= 68 + 72
= 140
但是 8 位补码的表示范围是:
-128 ~ +127
140 超过了最大正数 127,所以发生正溢出,OF = 1。
但是机器不会停在那里。机器仍然会按 8 位补码运算给出结果。
先算 2y:
y = DCH = 1101 1100
算术左移一位:
1101 1100 << 1 = 1011 1000 = B8H
所以:
x - 2y = 44H - B8H
减法用加法实现:
44H - B8H
= 44H + B8H 的补码相反数
= 44H + (~B8H + 1)
计算:
B8H = 1011 1000
~B8H = 0100 0111 = 47H
~B8H + 1 = 0100 1000 = 48H
所以:
44H - B8H
= 44H + 48H
二进制相加:
0100 0100
+ 0100 1000
------------
1000 1100
结果就是:
1000 1100 = 8CH
所以第 21 题的机器结果是:
8CH,OF = 1
关键就在这里:8CH 是机器实际算出来并保留在寄存器里的 8 位结果,但由于 OF = 1,它不能作为正确的有符号补码结果来解释。
如果强行把 8CH 当作 8 位补码解释:
8CH = 1000 1100
无符号值 = 140
补码真值 = 140 - 256 = -116
这就变成了 -116,显然和真实数学结果 +140 不一致。这个“不一致”正是溢出的表现。
所以要分清两句话:
机器结果:8CH
真实数学结果:+140
8 位补码无法表示 +140
因此 OF = 1,机器结果作为有符号数无效
二、为什么溢出后会变成 8CH?
因为固定字长机器只保留低 n 位。
8 位机器中,所有运算结果最后都只能落在 8 位里。超过 8 位的部分要么被丢弃,要么通过标志位反映出来。
对于第 21 题:
真实数学结果 = 140
140 的二进制是:
140 = 1000 1100
它刚好是 8 位,但问题在于:8 位补码里,最高位是符号位。
8 位补码中:
0000 0000 ~ 0111 1111 表示 0 ~ +127
1000 0000 ~ 1111 1111 表示 -128 ~ -1
所以 1000 1100 在 8 位补码语境下不是 +140,而是 -116。
这就是补码有符号溢出的本质:二进制位形还在,但它已经落入了错误的符号区间。
可以这样理解:
数学上:68 + 72 = 140
机器上:
0100 0100 + 0100 1000 = 1000 1100
两个正数相加,结果最高位却变成 1,像负数
所以发生正溢出
这类题以后可以直接用这个规则判断:
正数 + 正数 = 负数,正溢出
负数 + 负数 = 正数,负溢出
异号相加,不溢出
第 21 题本质上就是:
68 + 72
两个正数相加,结果机器位形为:
1000 1100
最高位为 1,结果像负数,所以溢出。
三、第 20 题和第 21 题的区别
第 20 题是:
x/2 + 2y
已知:
x = 68
y = -36
所以:
x/2 + 2y
= 34 + 2 × (-36)
= 34 - 72
= -38
-38 在 8 位补码范围内,所以不溢出。
-38 的补码:
38 = 0010 0110
-38 = 1101 1010 = DAH
所以第 20 题是:
DAH,OF = 0
第 21 题是:
x - 2y = 140
超过 +127,所以:
8CH,OF = 1
两题的区别不是“机器能不能算出一个十六进制结果”,而是:
第 20 题:机器结果 DAH 能正确表示 -38,所以 OF = 0
第 21 题:机器结果 8CH 不能正确表示 +140,所以 OF = 1
四、CF 和 OF 的核心区别
CF 和 OF 都和“超过范围”有关,但它们服务的对象不同。
CF:Carry Flag,进位 / 借位标志,主要用于无符号数运算
OF:Overflow Flag,溢出标志,主要用于有符号补码运算
这句话非常重要。
同一串二进制,既可以被解释成无符号数,也可以被解释成有符号补码数。例如:
1000 1100
如果看成无符号数:
1000 1100 = 140
如果看成 8 位补码:
1000 1100 = -116
机器加法器本身并不知道程序员想把它当有符号数还是无符号数。机器只负责二进制相加,然后设置标志位。到底该看 CF 还是 OF,取决于这次运算被当作什么类型来解释。
五、CF:无符号数的进位 / 借位
CF 主要用于无符号数。
对于加法:
如果最高位向更高位产生进位,则 CF = 1
否则 CF = 0
例如 8 位无符号加法:
1111 1111 = 255
+ 0000 0001 = 1
------------
1 0000 0000
8 位寄存器只能保留低 8 位:
0000 0000
但最高位产生了进位,所以:
CF = 1
这表示无符号加法溢出:
255 + 1 = 256
而 8 位无符号数范围是:
0 ~ 255
所以超范围。
但是如果从有符号补码角度看:
1111 1111 = -1
0000 0001 = +1
那么:
-1 + 1 = 0
有符号运算并没有溢出,所以:
OF = 0
这个例子说明:
CF = 1 不一定 OF = 1
OF = 1 也不一定 CF = 1
它们不是一回事。
六、OF:有符号补码的溢出
OF 主要用于有符号补码运算。
补码加法判断 OF,最常用的是:
同号相加,结果变号,则 OF = 1
异号相加,不会溢出
例如第 21 题中的核心加法:
0100 0100 = +68
+ 0100 1000 = +72
------------
1000 1100
两个操作数都是正数,结果却变成最高位为 1,好像是负数。
所以:
OF = 1
但是这个加法有没有产生最高进位呢?
0100 0100 + 0100 1000 = 1000 1100
没有超过 8 位,没有产生第 9 位进位,所以:
CF = 0
这就是非常典型的情况:
OF = 1,CF = 0
含义是:
作为有符号补码运算,它溢出了;
作为无符号加法,68 + 72 = 140,没有超过 255,所以没有无符号进位。
七、同一个结果,CF 和 OF 可以不同
用几个 8 位例子对比一下更清楚。
| 运算 | 机器结果 | 无符号角度 | 有符号角度 | CF | OF |
|---|---|---|---|---|---|
FFH + 01H | 00H | 255 + 1 = 256,无符号溢出 | -1 + 1 = 0,不溢出 | 1 | 0 |
44H + 48H | 8CH | 68 + 72 = 140,未超过 255 | 68 + 72 = 140,超过 +127 | 0 | 1 |
80H + 80H | 00H | 128 + 128 = 256,无符号溢出 | -128 + -128 = -256,有符号溢出 | 1 | 1 |
01H + 01H | 02H | 正常 | 正常 | 0 | 0 |
所以不要把 CF 和 OF 混成一个“溢出标志”。
更准确地说:
CF 判断无符号数是否超出范围;
OF 判断有符号补码数是否超出范围。
八、减法和比较时,CF 怎么理解?
减法中,CF 通常表示借位。
例如无符号数:
0 - 1
显然不够减,需要借位,所以:
CF = 1
在固定 8 位中:
0000 0000 - 0000 0001 = 1111 1111
机器结果是 FFH,也就是无符号的 255。这不是数学上的 -1,而是无符号模运算回绕。
所以无符号比较时,常通过减法来设置标志位。
例如比较:
a < b
机器内部可以做:
a - b
如果 a - b 需要借位,说明:
a < b
于是:
CF = 1
所以无符号比较常用规则是:
a < b 看 CF = 1
a == b 看 ZF = 1
a <= b 看 CF = 1 或 ZF = 1
其中 ZF 是零标志位,表示结果是否为 0。
九、OF 在有符号比较中的作用
有符号比较不能简单看最高位,因为有符号运算可能溢出。
例如判断:
a < b
机器可以计算:
a - b
如果结果是负数,通常说明 a < b。但是如果减法发生有符号溢出,结果的符号位可能是错的。这时就需要结合 OF 修正。
所以有符号比较常用:
SF 和 OF
其中:
SF:Sign Flag,符号标志,等于结果最高位
OF:Overflow Flag,有符号溢出标志
ZF:Zero Flag,零标志
常见规则是:
有符号 a < b:看 SF ⊕ OF = 1
有符号 a <= b:看 ZF = 1 或 SF ⊕ OF = 1
考研里不一定要求把这几个跳转条件全部背下来,但要知道大方向:
无符号比较:主要看 CF、ZF
有符号比较:主要看 SF、OF、ZF
第 22 题问 CF / OF,本质就是让判断:这次比较是无符号比较,还是有符号比较。
十、第 22 题为什么看 CF,而不是 OF?
第 22 题代码是:
int si = 65536;
short i = si;
unsigned j = 0;
if (i <= j - 1)
printf("王道");
else
printf("计算机教育");
先看:
short i = si;
在考研常见设定中:
int 32 位
short 16 位
unsigned 32 位
65536 的十六进制是:
65536 = 0x00010000
赋给 16 位 short,只保留低 16 位:
0x00010000 的低 16 位 = 0x0000
所以:
i = 0
再看:
unsigned j = 0;
那么:
j - 1
不是有符号的 0 - 1 = -1,而是无符号运算:
0u - 1u = UINT_MAX
在 32 位 unsigned 中:
UINT_MAX = 0xFFFFFFFF = 2³² - 1
然后比较:
i <= j - 1
由于右边是 unsigned,左边的 i 也会被转换成 unsigned。
于是比较变成:
0u <= 0xFFFFFFFFu
这个条件当然成立,所以输出:
王道
因为这次比较已经变成了无符号比较,所以判断条件依赖的是无符号比较标志,也就是主要看:
CF、ZF
而选项里通常把无符号比较归为:
CF
所以第 22 题选:
CF,王道
十一、第 22 题如果按有符号比较,会发生什么?
如果没有 unsigned j 这个陷阱,直觉上可能会想:
j = 0
j - 1 = -1
i = 0
0 <= -1
这当然是假。
如果是有符号比较,确实应该输出:
计算机教育
但问题是 C 语言里,只要表达式中混入了 unsigned,很多时候另一个有符号数会被转换成无符号数。
所以实际不是比较:
0 <= -1
而是比较:
0u <= 4294967295u
这就是真。
这道题的本质陷阱就是:
unsigned 会把整个表达式拉到无符号语境中。
十二、做题时怎么快速判断看 CF 还是 OF?
可以直接按类型判断。
如果题目说:
无符号数加减、无符号数比较
重点看:
CF
如果题目说:
补码、有符号整数、int、short、signed
重点看:
OF
但 C 语言题要特别注意:变量声明里只要出现 unsigned,表达式可能被转换成无符号运算。
所以第 22 题虽然有 short i,但右边有:
unsigned j
于是整个比较转为无符号比较,看 CF,不是看 OF。
可以整理成一句考试用判断:
CF 管无符号进位/借位,OF 管有符号补码溢出。
再细一点:
无符号数:范围是 0 ~ 2ⁿ - 1,超了看 CF。
有符号补码:范围是 -2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1,超了看 OF。
十三、回到你的疑问:溢出时到底输出什么?
最后再把这个点压实。
以 8 位补码为例,机器运算永远输出 8 位结果:
44H + 48H = 8CH
从二进制看:
0100 0100 + 0100 1000 = 1000 1100
所以寄存器里就是:
1000 1100
也就是:
8CH
但因为这是两个正数相加却得到负号位,所以:
OF = 1
因此:
机器输出:8CH
是否可信:作为有符号补码结果不可信
真实数学结果:140
溢出原因:140 超过 8 位补码最大值 127
做补码溢出题时,一定要把这三件事分开:
1. 机器位形结果是多少?
2. 这个结果按补码解释成什么真值?
3. 真实数学结果是否超出补码表示范围?
第 21 题就是最典型的例子:
机器位形结果:8CH
按 8 位补码解释:-116
真实数学结果:+140
因为真实结果无法用 8 位补码表示,所以 OF = 1

本题应选 C。
这张图考的是 32 位补码一位乘法器,本质上对应考研里常说的 Booth 一位乘法思想。它不是普通无符号移位加法乘法,而是针对补码有符号数设计的乘法逻辑。
图中结构大致可以这样读:
被乘数放在寄存器 X 中,位数为 32 位;部分积放在 P 中,乘数放在 Y 中,P | Y 合起来构成 64 位寄存器;ALU 是 32 位的,每次只对部分积 P 和被乘数 X 做加法或减法;控制逻辑根据乘数末位及附加位判断本轮执行 +X、-X,还是不操作,然后再让 P | Y 整体右移一位。这个过程重复 32 次。
Booth 一位乘法的基本规则是看当前乘数最低位和附加位,常写成:
Y0 Y-1 = 00 :不操作
Y0 Y-1 = 01 :P = P + X
Y0 Y-1 = 10 :P = P - X
Y0 Y-1 = 11 :不操作
然后 P、Y、Y-1 整体算术右移一位
所以逐项判断如下。
A 项说“32 位无符号整数的乘法电路和该图没有区别”,这是错误的。无符号一位乘法通常只需要根据乘数位判断是否加被乘数,不需要根据相邻两位判断加法或减法,也不需要为了补码符号保持而进行算术右移。该图中明显有“加/减”控制信号,说明它不是普通无符号乘法器,而是补码乘法器。
B 项说“执行过程中 ALU 要么做加法,要么做减法,不可能执行空操作”,这是错误的。Booth 一位乘法中,当判断位组合为 00 或 11 时,本轮不需要对部分积加减被乘数,也就是可以空操作。只有 01 时加,10 时减。
C 项说“图中的乘积寄存器 P 和乘数寄存器 Y 所执行的右移是算术右移”,这是正确的。因为这是补码乘法,右移时必须保持符号位。更准确地说,是 P、Y 以及附加位整体构成的移位寄存器做算术右移,最高位补 P 的符号位,不能做逻辑右移。如果逻辑右移,高位补 0,会破坏负数的符号扩展,结果就不再是正确的补码乘法。
D 项说“计算完成后,若乘积寄存器 P 中的值不全为 0,则发生溢出”,这是错误的。两个 32 位补码数相乘,完整结果是 64 位,放在 P | Y 中,正常情况下并不存在 64 位结果溢出的问题。如果题目要求只保留低 32 位,那么判断溢出也不能简单看 P 是否全为 0。对于有符号补码乘法,若最终 64 位结果能够被低 32 位正确符号扩展表示,才不溢出。也就是说,高 32 位 P 应该是低 32 位 Y 符号位的扩展:
若 Y 的最高位为 0,则 P 应全为 0
若 Y 的最高位为 1,则 P 应全为 1
例如负数乘积的高位可能全为 1,这不代表溢出;所以 D 项把无符号乘法的部分判断思路错误套到了补码有符号乘法上。
因此本题结论是:
A 错
B 错
C 对
D 错
正确答案:C
这类题的快速识别方法是:只要看到 补码一位乘法 + 加/减控制 + P、Y 整体右移 + 附加判断位,基本就是 Booth 乘法。考点通常集中在三个地方:第一,ALU 不一定每轮都加减,可能空操作;第二,补码乘法右移必须是算术右移;第三,溢出判断不能简单看高位是否非 0,而要看高位是否为低位符号位的正确扩展。
对于这种类型的题目 ,这个结构我们是否需要熟记呢?它涉及到哪些知识 ,,本质上考的是什么东西?
这种题不需要把整张逻辑结构图一笔一画背下来,但需要熟记它背后的“结构模板”。也就是说,不要求记住每根线怎么连、方框位置怎么摆,但必须看到 X、P、Y、ALU、右移、计数器、控制逻辑 这些部件时,能立刻判断出:这是 补码一位乘法,也就是 Booth 乘法的硬件实现。
它本质上不是在考画图,而是在考:补码乘法算法如何映射成硬件数据通路和控制逻辑。
一、这种结构要不要熟记?
要熟,但不是死背图形,而是熟记它的几个关键部件和作用。
对于 32 位补码一位乘法器,可以把结构压缩成下面这个模型:
X:被乘数寄存器,存放被乘数
P:乘积高位 / 部分积寄存器,32 位
Y:乘数寄存器,32 位
P | Y:合起来构成 64 位乘积寄存器
ALU:对 P 和 X 做加法或减法
控制逻辑:根据 Y 的最低位和附加位判断加、减或不操作
计数器:控制循环次数,32 位乘法做 32 次
右移逻辑:每轮之后 P、Y 和附加位整体右移一位
如果从做题角度压缩记忆,可以记成一句话:
补码一位乘法 = P 与 X 加/减 + P、Y、附加位整体算术右移 + 做 n 轮
所以结构图不用完整背,但必须记住这几个不变量:
第一,X 是被乘数寄存器,不参与右移。
第二,P 是部分积寄存器,要和 X 送入 ALU 做加减。
第三,Y 是乘数寄存器,会和 P 一起右移。
第四,控制逻辑不是只看一位,而是看 Y0 和附加位 Y-1。
第五,每轮可能加、可能减、也可能什么都不做。
第六,补码乘法右移必须是算术右移,而不是逻辑右移。
这几个点熟了,图形怎么变都能做。
二、它涉及哪些知识点?
这类题看起来是“乘法器结构”,但其实同时串了四块内容。
第一块是 补码表示与补码加减法。因为被乘数和乘数都是补码形式,所以硬件里不需要单独判断正负号再取绝对值,而是直接用补码加减完成乘法。这也是 Booth 乘法能直接处理有符号数的原因。
第二块是 定点乘法算法。考研里常见的乘法有无符号乘法、原码一位乘法、补码一位乘法。它们的共同点是“逐位处理乘数,每轮移位”,区别在于是否需要减法、右移方式、符号如何处理。
第三块是 数据通路结构。也就是寄存器、ALU、移位器、控制逻辑、计数器之间如何配合。题目给图时,通常不是让你设计电路,而是让你判断图中某个部件的功能或某个选项的说法是否正确。
第四块是 溢出与结果位数。两个 32 位数相乘,完整乘积需要 64 位保存。若题目默认结果存在 P | Y 这个 64 位寄存器中,一般不按 32 位结果判断溢出。如果题目要求只保留 32 位结果,则有符号乘法的溢出判断要看高 32 位是否是低 32 位符号位的扩展,而不是简单看高 32 位是否全 0。
三、补码一位乘法的核心规则
补码一位乘法,也就是 Booth 一位乘法,最核心的控制规则是看 Y0 和附加位 Y-1。
设 Y0 是乘数寄存器当前最低位,Y-1 是附加位,初始为 0。
Y0 Y-1 = 00 :P 不变
Y0 Y-1 = 01 :P = P + X
Y0 Y-1 = 10 :P = P - X
Y0 Y-1 = 11 :P 不变
然后 P、Y、Y-1 整体算术右移一位
这张图里的“加/减”控制信号,就是为了实现 P + X 或 P - X。如果只是普通无符号乘法,一般只需要根据乘数位决定是否加被乘数,不需要这种 Booth 式的加减判断。
所以看到图中有 加/减控制,就要警觉:这不是普通无符号乘法,而是补码 Booth 乘法。
四、这种题可以直接套用什么方法?
做这种结构判断题,可以直接套一个四步法。
第一步:先判断是哪种乘法器
看题干关键词。
如果题干说“补码一位乘法”,并且图中有 加/减 控制,那么基本就是 Booth 乘法。
如果题干说“无符号乘法”或只根据乘数位判断是否加被乘数,一般是普通移位加法乘法。
如果题干说“原码一位乘法”,通常是先处理符号位,数值部分按绝对值做乘法,符号单独确定。
本题明确说“32 位补码一位乘法”,所以算法定位就是 Booth 乘法。
第二步:识别寄存器分工
这一步是防止选项偷换概念。
X 是被乘数寄存器,通常保持不动。
Y 是乘数寄存器,会右移。
P 是部分积寄存器,和 Y 合起来保存中间结果。
P | Y 合起来是 64 位寄存器,最终结果也在这里。
ALU 只负责对 P 和 X 做加法或减法,不直接对整个 64 位乘积做加减。
所以看到选项说 P 和 Y 一起右移,这通常是对的;看到选项说 X 也跟着右移,通常就要怀疑。
第三步:判断每轮操作
补码 Booth 乘法每轮不一定加减,可能空操作。
这个点很常考。因为很多同学会以为“既然图里有 ALU,那每轮 ALU 必须做加法或减法”。实际上不是。
Booth 规则中:
00:不操作
01:加 X
10:减 X
11:不操作
所以如果选项说“执行过程中 ALU 要么加法,要么减法,不可能空操作”,这是错的。
第四步:判断右移类型
这是本题最核心的判断点。
补码表示的是有符号数,右移时必须保持符号位,所以 P、Y、Y-1 整体右移应是 算术右移。
算术右移的含义是:最高位补原符号位。
逻辑右移的含义是:最高位补 0。
补码乘法中如果用逻辑右移,负数的符号扩展会被破坏,中间结果就会错。因此,凡是补码一位乘法,看到右移,一般优先判断为算术右移。
可以记成:
无符号乘法:通常逻辑右移
补码 Booth 乘法:整体算术右移
五、本质上到底考什么?
这类题本质上考的不是“乘法怎么算出具体结果”,而是考三个层次。
第一个层次是 算法规则:补码 Booth 乘法每轮根据 Y0Y-1 判断 +X、-X、不操作。
第二个层次是 硬件实现:为什么需要 P、Y、X、ALU、控制逻辑、计数器,每个部件在算法中对应什么动作。
第三个层次是 易错概念辨析:无符号乘法和补码乘法是否一样,ALU 是否每轮都工作,右移是算术右移还是逻辑右移,乘积是否溢出如何判断。
考研选择题通常就是围绕这些点设置干扰项。
例如本题四个选项的本质分别是:
A:考无符号乘法和补码乘法电路是否一样
B:考 Booth 乘法是否允许空操作
C:考补码乘法右移类型
D:考 32 位乘法结果与溢出判断
所以这道题不是孤立地考一张图,而是把补码表示、移位、ALU、乘法算法、溢出判断揉在一起考。
六、几个高频陷阱
第一,容易把补码一位乘法当成无符号乘法。
无符号乘法通常是“当前乘数位为 1 就加,为 0 就不加”,没有 +X / -X 的 Booth 判断。而补码 Booth 乘法要看相邻两位变化,所以会出现减法。
看到“加/减”控制信号,就不要再按普通无符号乘法理解。
第二,容易认为 ALU 每轮必须工作。
这是错的。00 和 11 都是不操作。硬件里可以让 ALU 不改变 P,或者通过控制信号使写入无效。题目说“不可执行空操作”,通常就是错项。
第三,容易把右移看成普通逻辑右移。
只要是补码有符号运算,右移通常要考虑符号保持。Booth 乘法中,P、Y、Y-1 整体右移是算术右移,最高位补 P 的符号位。
第四,容易用“高位不为 0”判断有符号乘法溢出。
这只适合某些无符号截断场景,不能直接套到补码有符号乘法。
如果两个 32 位补码数相乘,完整结果用 64 位保存,不应简单说 P 非 0 就溢出。负数乘积的高位可能全是 1,这是正常的符号扩展。
若只保留低 32 位,有符号溢出的判断应是:
低 32 位最高位为 0:高 32 位应全为 0
低 32 位最高位为 1:高 32 位应全为 1
否则表示低 32 位无法正确表示完整乘积,发生溢出
七、做题时的快速判断口诀
这类题可以记下面这一套:
补码乘法看 Booth,
两位决定加减无;
P 与 X 进 ALU,
P、Y 整体算右移;
做满 n 轮得 2n 位,
溢出别只看高位非零。
更简化一点:
补码一位乘法:
看 Y0Y-1,01 加,10 减,00/11 不动,整体算术右移。
这句话基本能解决大多数围绕补码一位乘法结构图的选择题。
八、复习时应该掌握到什么程度?
408 风格下,不需要把乘法器内部控制线路设计到门级电路,但要能做到以下程度:
看到结构图,能说出哪个寄存器存被乘数、哪个存乘数、哪个存部分积。
看到 加/减 控制,能判断这是补码 Booth 乘法的重要特征。
看到“每轮 ALU 必须加或减”这种说法,能判断错误,因为可能空操作。
看到“右移”相关说法,能判断补码乘法应该是算术右移。
看到“P 不全为 0 就溢出”这种说法,能判断错误,因为有符号数高位可能是符号扩展。
所以这类题最重要的不是会不会手算一个很长的乘法过程,而是能把 算法规则、寄存器含义、移位方式、溢出判断 四件事对应起来。掌握这四点,结构图换一种画法也不会影响判断。

本题答案:A。
这道题的关键不是让你真的手算 32 次除法循环,而是考 32 位补码整数除法中的特殊溢出情况。
题干说:
除数寄存器 Y
余数/商寄存器 Q
Y、Q 均为补码表示
问:什么初始值下除法执行时间最短?
在这种除法器中,正常的 32 位整数除法一般要经过多次“左移 + 加/减 + 上商”的迭代过程。图中也有计数器 Cₙ,说明正常情况下要按位循环执行。
所以如果问“执行时间最短”,通常不是比较哪个商更简单,而是要看有没有 一开始就能判定异常 的情况。对于 32 位补码整数除法,最典型的异常就是:
-2³¹ ÷ (-1) = +2³¹
但是 32 位补码整数的表示范围是:
-2³¹ ~ 2³¹ - 1
也就是说,+2³¹ 超出了 32 位补码正数的最大范围,因此发生 商溢出。这种情况不需要完整执行 32 轮除法,可在开始阶段直接判定溢出,因此执行时间最短。
先把选项中的十六进制数转换成 32 位补码真值:
FFFF FFFF = -1
8000 0000 = -2³¹
逐项判断。
A 项:
Y = FFFF FFFF = -1
Q = 8000 0000 = -2³¹
表示:
Q ÷ Y = (-2³¹) ÷ (-1) = +2³¹
但 32 位补码最大正数是 2³¹ - 1,所以 +2³¹ 不能表示,发生商溢出。可以提前终止,执行时间最短。
B 项:
Y = 8000 0000 = -2³¹
Q = FFFF FFFF = -1
表示:
(-1) ÷ (-2³¹) = 0,余数为 -1
商为 0,可以表示,不溢出,需要正常执行除法过程。
C 项:
Y = FFFF FFFF = -1
Q = FFFF FFFF = -1
表示:
(-1) ÷ (-1) = 1
商为 1,可以表示,不溢出。
D 项:
Y = 8000 0000 = -2³¹
Q = 8000 0000 = -2³¹
表示:
(-2³¹) ÷ (-2³¹) = 1
商为 1,也可以表示,不溢出。
因此只有 A 会产生补码整数除法中特殊的商溢出。
结论:
正确答案:A
这类题的固定做法是:先把 FFFF FFFF 和 8000 0000 识别出来。
FFFF FFFF = -1
8000 0000 = 最小负数 = -2³¹
然后重点检查是否出现:
最小负数 ÷ (-1)
只要是 32 位补码整数除法:
0x80000000 ÷ 0xFFFFFFFF
= -2³¹ ÷ (-1)
= +2³¹
这个结果超出 32 位补码范围,发生商溢出。
所以看到这种题,不要真的去模拟除法器。它本质上考的是 补码整数除法的溢出边界,尤其是 最小负数 ÷ -1 这一种特殊情况。

25~28 题的答案分别是:
25:D
26:B
27:A
28:C
这几题本质上都在考“补码表示、符号扩展、定点补码运算溢出、C 语言整型提升规则”,属于计算机组成原理中“数据的表示和运算”的高频题型。
第25题:C 语言中 int、short 混合运算
题意是:32 位机器,x 和 z 是 int 型,y 是 short 型。
已知:
x = 127;
y = -9;
z = x + y;
要求判断执行后 x、y、z 的机器数表示。
x = 127,int 型占 32 位,所以:
x = 0000007FH
y = -9,short 型占 16 位。先写出 +9:
+9 = 0009H
16 位补码表示 -9,就是对 0009H 求补码:
0009H -> FFF7H
所以:
y = FFF7H
注意这里最容易错的是把 -9 写成 FFF9H。FFF9H 其实表示的是 -7,不是 -9。
执行:
z = x + y;
在 C 语言中,short 参与表达式运算时要先进行整型提升。也就是说,y 会从 16 位 short 提升为 32 位 int。
因为 y 是负数,所以要进行符号扩展:
y = FFF7H -> FFFFFFF7H
然后计算:
0000007FH + FFFFFFF7H = 00000076H
真值角度看就是:
127 + (-9) = 118
118 的 32 位补码就是:
00000076H
所以第25题选:
D
x = 0000007FH,y = FFF7H,z = 00000076H
这题的核心陷阱是两个:第一,-9 的 16 位补码是 FFF7H;第二,short 和 int 混合运算时,short 要先符号扩展为 int。
第26题:8位补码乘法是否溢出
题意是:四个整数用 8 位补码表示:
r1 = FEH
r2 = F2H
r3 = 90H
r4 = F8H
运算结果仍然存在一个 8 位寄存器中,判断哪一个乘法会溢出。
8 位补码表示范围是:
-128 ~ +127
先把每个机器数转换成真值。
FEH 是 8 位补码:
FEH = 11111110
最高位是 1,说明是负数。其真值为:
FEH = 254
254 - 256 = -2
所以:
r1 = -2
同理:
r2 = F2H = 242 - 256 = -14
r3 = 90H = 144 - 256 = -112
r4 = F8H = 248 - 256 = -8
逐项计算:
A. r1 × r2 = (-2) × (-14) = 28
B. r2 × r3 = (-14) × (-112) = 1568
C. r1 × r4 = (-2) × (-8) = 16
D. r2 × r4 = (-14) × (-8) = 112
8 位补码能表示的最大正数是 127,所以只有:
1568
超出了 8 位补码范围。
所以第26题选:
B
这题不要直接在十六进制上硬算,最快方法是先转真值,再看结果是否在 -128 ~ +127 内。
第27题:8位补码下计算 z = 2x + y/2
题意是:某字长为 8 位的计算机中,已知:
[x]补 = 11110100
[y]补 = 10110000
若:
z = 2x + y/2
求 z 的机器数。
先把 x、y 从补码转为真值。
x = 11110100,最高位是 1,所以是负数。它对应的无符号值是:
11110100 = F4H = 244
8 位补码真值为:
244 - 256 = -12
所以:
x = -12
y = 10110000,无符号值是:
10110000 = B0H = 176
真值为:
176 - 256 = -80
所以:
y = -80
代入表达式:
z = 2x + y/2
z = 2 × (-12) + (-80)/2
z = -24 - 40
z = -64
8 位补码中,-64 的表示是:
先写出 +64:
01000000
取反加一:
10111111 + 1 = 11000000
所以:
[z]补 = 11000000
选项中写成分组形式就是:
1 1000000
所以第27题选:
A
这题要注意,y/2 对负数来说,在计算机组成原理中常按补码算术右移理解。这里 -80 / 2 = -40,能整除,不涉及向上还是向下取整的问题。
第28题:8位定点补码运算判断溢出
题意是:
x = 103
y = -25
判断下列表达式采用 8 位定点补码运算时,哪个会溢出。
8 位补码范围仍然是:
-128 ~ +127
逐项看真值结果即可。
A:
x + y = 103 + (-25) = 78
78 在范围内,不溢出。
B:
-x + y = -103 + (-25) = -128
-128 是 8 位补码可以表示的最小值,所以不溢出。
注意:很多人会误以为 -128 溢出,但 8 位补码范围是 -128 ~ +127,所以 -128 可以表示。
C:
x - y = 103 - (-25) = 128
128 超过了 8 位补码最大正数 127,所以溢出。
D:
-x - y = -103 - (-25) = -78
-78 在范围内,不溢出。
所以第28题选:
C
这题用真值判断最快。只要结果超出 -128 ~ +127,就一定溢出。
这类题的统一做法
这几题可以套一个固定流程。
第一步,看字长。
如果是 8 位补码,范围是:
-128 ~ +127
如果是 n 位补码,范围是:
-2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1
第二步,把机器数转真值。
对于 8 位补码:
最高位为 0:直接看成正数
最高位为 1:真值 = 无符号值 - 256
例如:
F2H = 242
242 - 256 = -14
第三步,先用真值算出结果。
尤其是判断溢出时,不要急着二进制硬加,真值法最快。
第四步,看结果是否超出表示范围。
8 位补码只要结果不在:
-128 ~ +127
内,就溢出。
第五步,如果题目问机器数,再把真值转回补码。
负数转补码可以用两种方法:
方法一:正数原码取反加一
方法二:真值 + 2ⁿ
比如 8 位补码表示 -64:
-64 + 256 = 192
192 = C0H = 11000000
这类题真正考的不是复杂计算,而是几个基本点是否稳:补码范围、负数补码转真值、真值转补码、符号扩展、以及 C 语言整型提升规则。

答案汇总:
30:B
31:A
32:B
33:C
34:D
35:D
第30题:逻辑右移与算术右移
原机器数为:
1101 1000
题目问分别进行“逻辑右移 1 位”和“算术右移 1 位”。
逻辑右移的规则是:最高位补 0,低位移出。
1101 1000 逻辑右移 1 位
= 0110 1100
算术右移的规则是:最高位补原符号位。原数最高位是 1,所以右移后最高位仍补 1。
1101 1000 算术右移 1 位
= 1110 1100
所以结果依次是:
0110 1100,1110 1100
选 B。
这类题的关键是:逻辑右移不管符号,统一补 0;算术右移保留符号,正数补 0,负数补 1。
第31题:减法中的 CF 和 OF
题目给出减法指令:
(R1) - (R2) -> R3
已知:
R1 = FFFF FFFFH
R2 = FFFF FFF0H
先按无符号数看:
FFFF FFFFH = 2³² - 1
FFFF FFF0H = 2³² - 16
所以:
FFFF FFFFH - FFFF FFF0H = 0000 000FH
即结果为 15。
对于减法来说,CF 表示借位标志。判断方法很简单:
若无符号数 x < y,则 x - y 需要借位,CF = 1
若无符号数 x >= y,则不需要借位,CF = 0
这里:
FFFF FFFFH > FFFF FFF0H
所以不借位,CF = 0。
再看 OF。OF 是有符号溢出标志。
FFFF FFFFH 表示 -1
FFFF FFF0H 表示 -16
所以:
-1 - (-16) = 15
15 在 32 位补码范围内,不溢出,因此 OF = 0。
所以:
CF = 0,OF = 0
选 A。
这类题必须分清:CF 管无符号借位,OF 管有符号溢出。不要把结果最高位、正负号和 CF 混在一起判断。
第32题:继续考减法的 OF 和 CF
题目已经告诉:
x = 100,y = 200
执行 x - y
OF = 0,CF = 1
这其实是在提示 CF 的判定规则:减法中如果无符号意义下 x < y,则需要借位,CF = 1。
现在问:
x = 10,y = -20
执行 x - y
先看有符号结果:
10 - (-20) = 30
30 在 int 的表示范围内,所以没有有符号溢出:
OF = 0
再看 CF。CF 要从无符号角度看。
在 32 位补码机器中,-20 的机器数不是“负数”,而是一个很大的无符号数:
-20 的补码无符号解释 = 2³² - 20
所以从无符号减法角度看:
10 - (2³² - 20)
显然 10 小于 2³² – 20,需要借位,因此:
CF = 1
所以:
OF = 0,CF = 1
选 B。
这题最容易错在把 y = -20 直接当成普通数学负数去判断 CF。CF 不管有符号语义,它只看机器数的无符号减法是否借位。
第33题:int 转 short,再转 int
代码为:
int i = -32777;
short si = i;
int j = si;
统考默认环境一般按:
int:32 位
short:16 位
补码表示
16 位 short 的范围是:
-32768 ~ 32767
而 -32777 已经超出了 short 的范围。
先求 -32777 的低 16 位。
因为:
32777 = 32768 + 9 = 8009H
所以 32 位补码中:
-32777 = FFFF 7FF7H
赋值给 short 时,只保留低 16 位:
7FF7H
7FF7H 的最高位是 0,所以作为 short 解释时是正数:
7FF7H = 32759
再赋值给 int:
j = 32759
选 C。
这类强制类型转换题要抓住两步:长整数转短整数,截断低位;短整数转长整数,看原类型是否有符号,有符号数要符号扩展。这里截断后最高位为 0,所以扩展后仍是正数。
第34题:整数乘法运算叙述判断
题目问错误的是哪一项。
A:用阵列乘法器实现的乘运算可以在一个时钟周期内完成。
这在组成原理考法中一般认为正确。阵列乘法器属于硬件并行乘法器,可以通过组合逻辑并行产生部分积并求和,速度快,可以设计成一个时钟周期完成。
B:用 ALU 和移位器实现的乘运算无法在一个时钟周期内完成。
这通常正确。用 ALU 和移位器实现乘法,往往对应移位加法的迭代过程,每次处理一位或若干位,通常需要多个时钟周期。
C:变量与常数的乘运算可编译优化为若干移位及加减运算指令。
正确。例如:
x × 8 可以优化为 x << 3
x × 9 可以优化为 (x << 3) + x
x × 15 可以优化为 (x << 4) - x
这叫强度削弱,是常见编译优化。
D:两个变量的乘运算无法编译转换为移位及加法等指令的循环实现。
错误。两个变量相乘当然可以用软件循环实现,比如根据乘数的每一位决定是否累加被乘数,并不断移位。这正是乘法器的基本思想,只不过可以由硬件做,也可以由软件指令序列模拟。
因此错误项是 D。
这题考的不是复杂乘法算法,而是区分“硬件乘法器”“迭代移位加法”“编译优化”。看到“无法”这种绝对说法要特别警惕。
第35题:8 位补码减法与溢出
已知:
[x]补 = A3H
[y]补 = 75H
机器字长为 8 位,都是带符号整数。
先还原真值:
A3H = 1010 0011B
最高位为 1,是负数。其真值为:
A3H = 163
163 - 256 = -93
所以:
x = -93
再看 y:
75H = 0111 0101B
最高位为 0,是正数:
y = 117
数学上:
x - y = -93 - 117 = -210
但 8 位补码能表示的范围是:
-128 ~ 127
-210 超出范围,所以一定溢出:
OF = 1
再看机器实际得到的结果:
A3H - 75H
= A3H + (-75H)
75H 的相反数补码为:
75H = 0111 0101
按位取反:1000 1010
加 1:1000 1011 = 8BH
所以:
A3H + 8BH = 12EH
8 位机器只保留低 8 位:
2EH
2EH 的十进制是:
2 × 16 + 14 = 46
所以机器得到的结果是 46,但这是溢出后的错误结果。
因此:
x - y 的机器结果 = 46
OF = 1
选 D。
这题的关键是:数学真值是 -210,但机器结果按 8 位补码截断后变成 46。题目选项问的是“通过补码加减运算得到的 x – y 的值及 OF 标志”,所以要填机器运算结果和溢出标志,即 46,1。
所以在35题里面,我们知道如果两个数如果它溢出的话,实际上想要求最后输出的值是把一个数转换成补码,相当于补码的补码,对吧? 在33题里面,在超出了范围里,求第16位该如何快速求呢?我没有看懂这个式子
不是“补码的补码”这个说法最准确,而应理解为:
机器做补码加减法时,不管是否溢出,硬件都会按固定字长只保留低 n 位。溢出只是说明这个 n 位结果不能代表真实数学结果。
所以第35题的本质是:
8 位补码运算:
[x - y]补 = [x]补 + [-y]补
题目给:
[x]补 = A3H
[y]补 = 75H
要做 x - y,机器实际做的是:
[x]补 + [-y]补
而 [-y]补 怎么来?就是对 [y]补 求相反数的补码。
对于补码来说,一个数的相反数补码可以用:
按位取反 + 1
所以:
[y]补 = 75H = 0111 0101
[-y]补:
0111 0101 取反 = 1000 1010
1000 1010 + 1 = 1000 1011 = 8BH
于是:
A3H - 75H
= A3H + 8BH
= 1010 0011
+ 1000 1011
= 1 0010 1110
8 位机器只保留低 8 位:
0010 1110 = 2EH = 46
所以机器最后算出来的低 8 位结果是 46。
但真实数学结果是:
A3H 表示 -93
75H 表示 117
x - y = -93 - 117 = -210
8 位补码范围是:
-128 ~ 127
-210 超范围,所以发生溢出,OF = 1。
因此第35题是:
机器结果 = 46
OF = 1
也就是 D。
这里要特别区分两个东西:
真实数学结果:-210
机器低 8 位结果:46
溢出标志 OF:1
考研题如果问“补码加减运算得到的结果”,一般要写机器保留下来的 n 位结果;如果问“真值是否溢出”,再判断数学结果是否超范围。
第33题中,你没看懂的关键式子其实是在快速求“低 16 位”。
代码是:
int i = -32777;
short si = i;
int j = si;
默认按 408 常见考法:
int 是 32 位补码
short 是 16 位补码
int 转 short 时,保留低 16 位
short 转 int 时,符号扩展
所以核心问题是:
-32777 的低 16 位是多少?
方法一:用“模 2¹⁶”最快
16 位机器只保留低 16 位,本质等价于对 2¹⁶ = 65536 取模。
所以:
-32777 在 16 位中的结果
= -32777 mod 65536
= 65536 - 32777
= 32759
因此 short si 中保存的机器数对应的无符号值是 32759。
再看 32759 是否超过 32767:
32759 < 32767
所以它作为 16 位有符号 short 解释时还是正数:
si = 32759
再赋给 int,符号扩展后仍是:
j = 32759
所以选 C。
这个方法最适合考场使用。
方法二:用“越界绕回”理解
16 位 short 的范围是:
-32768 ~ 32767
而:
-32777 = -32768 - 9
它比 short 最小值还小 9。
补码溢出后会从正数最大端附近绕回来。具体是:
-32768 再减 1,会变成 32767
-32768 再减 2,会变成 32766
-32768 再减 9,会变成 32759
所以:
-32777 截断成 short 后 = 32759
这个方法甚至比算十六进制更快。
方法三:用十六进制低 16 位
先看:
32768 = 8000H
32777 = 32768 + 9 = 8009H
所以:
+32777 = 0000 8009H
要求:
-32777 的补码
32 位补码可以用:
2³² - 32777
但由于最后只要低 16 位,所以只看:
2¹⁶ - 32777
= 10000H - 8009H
= 7FF7H
也就是说:
-32777 的低 16 位 = 7FF7H
而:
7FF7H = 32759
所以最后:
j = 32759
这类题的统一做法可以记成一句话:
大类型转小类型:截断,保留低位。
小类型转大类型:扩展,有符号数符号扩展,无符号数零扩展。
第33题就是:
int -> short:保留低 16 位
short -> int:因为 short 是有符号类型,所以符号扩展
由于保留下来的低 16 位是:
7FF7H = 0111 1111 1111 0111
最高位是 0,所以符号扩展后还是正数:
0000 0000 0000 0000 0111 1111 1111 0111
因此 j = 32759。

3)x和y相减后的结果存放在寄存器 D中,寄存器 D中的内容是什么?此时溢出标志OF、符号标志 SF 各是什么?
下面按图中的两道综合题来做。核心是两件事:第一题考“同一串机器码按 unsigned / int 解释不同,以及逻辑移位、算术移位的结果”;第二题考“8 位补码加减法、溢出 OF、符号 SF”。
01 题:R1 = 8000 0004H,分别按 unsigned int 和 int 解释
已知 R1 是 32 位寄存器:
R1 = 8000 0004H
写成二进制大致是:
1000 0000 0000 0000 0000 0000 0000 0100
最高位是 1,所以如果按 unsigned int 看,它只是一个很大的正数;如果按 int 补码看,它是一个负数。
1)当 x 是 unsigned int 型时
unsigned int 没有符号位,32 位全部参与数值表示。
x = 8000 0004H
= 2³¹ + 4
= 2147483652
所以:
x 的真值 = 2147483652
题目说 unsigned int 型的乘除法采用逻辑移位。
乘以 2,相当于逻辑左移 1 位:
8000 0004H << 1 = 0000 0008H
因为最高位的 1 被移出去了,只保留低 32 位。
所以:
2x 存放在 R1 中的机器码 = 0000 0008H
如果从数学真值看:
2 × 2147483652 = 4294967304
但 32 位 unsigned int 的表示范围是:
0 ~ 2³² - 1
= 0 ~ 4294967295
所以结果超过了 32 位范围。计算机中只保留低 32 位,相当于对 2³² 取模:
4294967304 mod 2³² = 8
因此最终寄存器中结果对应的 unsigned 真值是:
2x 的真值 = 8
再看除以 2。unsigned int 除以 2 用逻辑右移 1 位,高位补 0:
8000 0004H >> 1 = 4000 0002H
所以:
x/2 存放在 R1 中的机器码 = 4000 0002H
其 unsigned 真值为:
4000 0002H = 2³⁰ + 2 = 1073741826
所以:
x/2 的真值 = 1073741826
整理如下:
| x 的类型 | x 的真值 | 2x 机器码 | 2x 真值 | x/2 机器码 | x/2 真值 |
|---|---|---|---|---|---|
| unsigned int | 2147483652 | 0000 0008H | 8 | 4000 0002H | 1073741826 |
这里最容易错的是把 8000 0004H 看成负数。它只有在 int 补码解释下才是负数,在 unsigned int 解释下是正数。
2)当 x 是 int 型时
int 默认按 32 位补码解释。最高位为 1,说明它是负数。
补码转真值可以用公式:
真值 = 无符号值 - 2³²
所以:
x = 8000 0004H
= 2147483652 - 4294967296
= -2147483644
因此:
x 的真值 = -2147483644
题目说 int 型的乘除法采用算术移位。
先看除以 2。负数算术右移时,高位补 1:
8000 0004H 算术右移 1 位 = C000 0002H
解释为 32 位补码:
C000 0002H = 3221225474 - 4294967296
= -1073741822
所以:
x/2 存放在 R1 中的机器码 = C000 0002H
x/2 的真值 = -1073741822
再看乘以 2。算术左移和逻辑左移在形式上都是:左移,低位补 0,高位移出。
8000 0004H << 1 = 0000 0008H
所以:
2x 存放在 R1 中的机器码 = 0000 0008H
如果按数学计算:
2x = 2 × (-2147483644)
= -4294967288
这个数已经超出 32 位 int 的表示范围:
-2³¹ ~ 2³¹ - 1
= -2147483648 ~ 2147483647
所以发生溢出。寄存器只保存左移后的低 32 位结果,即:
0000 0008H
按 int 补码解释为:
2x 的寄存器结果真值 = 8
整理如下:
| x 的类型 | x 的真值 | 2x 机器码 | 2x 结果真值 | x/2 机器码 | x/2 真值 |
|---|---|---|---|---|---|
| int | -2147483644 | 0000 0008H | 8 | C000 0002H | -1073741822 |
这一问的陷阱是:int 的 2x 数学真值应该是 -4294967288,但 32 位寄存器装不下,左移后实际保存的是 0000 0008H,再按补码解释就是 8。考研题通常问“存放在寄存器中的机器码”和“寄存器结果的真值”,要以有限字长运算后的机器码为准。
02 题:x = -68,y = -80,8 位补码加减法
题目给出:
x = -68
y = -80
A、B、C、D 都是 8 位寄存器
采用补码形式,含 1 位符号位
8 位补码表示范围是:
-128 ~ 127
1)寄存器 A 和 B 中的内容
先求 x = -68 的 8 位补码。
正数 68 的二进制为:
68 = 0100 0100B = 44H
负数补码 = 正数原码按位取反再加 1:
0100 0100
取反:1011 1011
加 1:1011 1100
所以:
-68 的补码 = 1011 1100B = BCH
因此:
A = BCH
再求 y = -80。
80 = 0101 0000B = 50H
取反加 1:
0101 0000
取反:1010 1111
加 1:1011 0000
所以:
-80 的补码 = 1011 0000B = B0H
因此:
B = B0H
答案:
A = BCH
B = B0H
2)x 和 y 相加,结果存放在 C 中
计算:
x + y = -68 + (-80) = -148
但 8 位补码的范围是:
-128 ~ 127
-148 超出了表示范围,所以一定发生溢出。
用机器码加法验证:
BC
+ B0
----
16C
8 位寄存器只能保存低 8 位:
C = 6CH
6CH 的二进制是:
0110 1100
最高位是 0,所以符号标志:
SF = 0
两个负数相加,却得到一个正数结果,这是典型的补码溢出:
OF = 1
所以:
C = 6CH
OF = 1
SF = 0
注意,C = 6CH 按 8 位补码解释是真值 +108,这不是数学上的 -148,而是溢出后寄存器中保留下来的错误结果。
3)x 和 y 相减,结果存放在 D 中
这里默认理解为:
x - y
即:
-68 - (-80) = 12
数学结果 12 在 8 位补码范围内,所以不会溢出。
用机器码计算:
x - y = x + (-y)
已知:
y = -80
所以:
-y = +80
+80 的 8 位补码是:
0101 0000B = 50H
于是:
BC
+ 50
----
10C
只保留低 8 位:
D = 0CH
0CH 的二进制是:
0000 1100
最高位是 0,所以:
SF = 0
结果没有超出 -128 ~ 127,所以:
OF = 0
因此:
D = 0CH
OF = 0
SF = 0
这两题的做题规律
第一题看到 8000 0004H,不要立刻说它是负数。必须先看题目给的是 unsigned int 还是 int。同一串机器码,按 unsigned 解释是 2147483652,按 int 补码解释是 -2147483644。
第二题判断 OF 时,不要只看最高位,也不要和 CF 混淆。补码有符号加法的溢出判断常用规则是:
同号相加,结果异号,则 OF = 1
异号相加,一定不溢出
对于减法:
x - y = x + (-y)
转成加法后再判断即可。
本题答案汇总:
01 题:
unsigned int:
x = 2147483652
2x 机器码 = 0000 0008H,真值 = 8
x/2 机器码 = 4000 0002H,真值 = 1073741826
int:
x = -2147483644
2x 机器码 = 0000 0008H,寄存器结果真值 = 8,发生溢出
x/2 机器码 = C000 0002H,真值 = -1073741822
02 题:
A = BCH
B = B0H
x + y:
C = 6CH
OF = 1
SF = 0
x - y:
D = 0CH
OF = 0
SF = 0
乘法指令阵列乘法实现的乘法指令以及alu和位移显示的乘法指令,这些知识点我不太清楚,能给我讲解一下吗?并且一小问,当取乘积的低n位作为乘法结果时,在判断是否溢出,你既然只取低n位,那么你又是如何知道高n位结果呢?这么多道题目下来,既然有符号整数加减,无符号整数加减,这四种运算都对于一串二进制位进行解释,那么,我们课本上介绍了那么加减法运算器是否都是可以视为这种同一种?并且乘除计算器又该如何理解呢?就像在第四题里面提到了,Alu位移器,寄存器及相应控制逻辑这些内容
可以把这部分统一理解成一句话:加减乘除运算器处理的本质都是二进制位串,所谓有符号、无符号,主要区别不在“怎么加”,而在“怎么解释结果、怎么判断溢出、乘除时是否需要符号扩展和修正”。
第 04 题里提到的“阵列乘法器”“用 ALU 和移位器实现的乘法指令”,其实是在区分两种乘法硬件实现方式:一种偏“串行迭代”,一种偏“并行硬件”。
一、先把“ALU、移位器、寄存器、控制逻辑”放到一张图里理解
组成原理里讲运算器时,不要把“运算器”只理解成一个加法器。一个典型 CPU 内部执行算术运算,大致涉及这些部件:
寄存器:保存操作数、部分结果、最终结果
ALU:做加法、减法、逻辑与或非异或、比较等
移位器:完成左移、右移、算术移位、逻辑移位
控制逻辑:决定每一步该谁工作、移几位、加不加、循环几次、结果写到哪里
比如计算乘法 x × y,如果没有专门乘法器,本质上可以拆成:
判断乘数某一位是不是 1
如果是 1,就把被乘数左移若干位后加到部分积中
然后继续检查下一位
这就需要:
寄存器保存 x、y、部分积
移位器负责 x << i 或者整体移位
ALU 负责加法
控制逻辑负责循环、判断、调度
所以题目里说“基于 ALU、位移器、寄存器及相应控制逻辑实现乘法指令”,意思不是说 ALU 本身会乘法,而是说:乘法指令虽然在指令层面是一条指令,但硬件内部用多轮加法和移位把乘法做出来。
二、没有乘法指令、ALU 移位实现乘法指令、阵列乘法器,这三者的区别
这三种情况可以按“软件实现、串行硬件实现、并行硬件实现”来理解。
第一种是没有乘法指令。这时程序里的 x * y 不能直接翻译成一条机器乘法指令,只能由编译器生成一段指令序列,例如:
初始化 result = 0
循环检查 y 的每一位
如果当前位是 1,则 result = result + x
x 左移 1 位
y 右移 1 位
循环 n 次
这时每一步都要取指、译码、执行,还要有循环跳转,所以慢。它是“软件层面用很多条指令模拟乘法”。
第二种是有乘法指令,但乘法指令内部由 ALU + 移位器 + 寄存器 + 控制逻辑实现。这时程序层面看起来有一条 MUL 指令,但 CPU 内部仍然要重复执行“移位、判断、加法”的过程。区别是这些步骤在 CPU 控制逻辑内部完成,不需要每一步都暴露成程序中的多条普通指令,所以比软件模拟快。
第三种是阵列乘法器实现的乘法指令。阵列乘法器是专门为乘法设计的组合逻辑或较高并行度硬件。它可以同时生成很多部分积,并通过加法器阵列把这些部分积快速相加。它的硬件成本更高,但速度更快。
所以考研题里常见判断是:
没有乘法指令:最慢
ALU + 移位器实现乘法指令:中间
阵列乘法器实现乘法指令:最快
这里的“最快”和“最慢”不是说某个具体 CPU 一定如此,而是从组成原理的典型模型出发:并行硬件越多,执行时间越短;软件循环越多,执行时间越长。
三、用 ALU 和移位器实现乘法,本质是什么
以无符号乘法为例,假设乘数 y 是 8 位:
y = y7 y6 y5 y4 y3 y2 y1 y0
那么:
x × y = y0 × x
+ y1 × (x << 1)
+ y2 × (x << 2)
+ ...
+ y7 × (x << 7)
如果某一位 yi = 0,对应部分积就是 0;如果 yi = 1,对应部分积就是 x << i。
例如:
13 × 11
13 = 0000 1101
11 = 0000 1011
因为 11 = 8 + 2 + 1,所以:
13 × 11 = 13 × (8 + 2 + 1)
= (13 << 3) + (13 << 1) + 13
= 104 + 26 + 13
= 143
这就是“移位 + 加法”实现乘法的本质。
如果是有符号乘法,情况会复杂一点。常见思路有两种:
一种是先把符号拿出来,转成绝对值做无符号乘法,最后根据符号修正结果。
负 × 正 = 负
正 × 负 = 负
负 × 负 = 正
另一种是直接基于补码做乘法,比如 Booth 算法。这类算法会根据乘数相邻位的变化决定加、减或不操作,适合补码有符号乘法。408 一般不会要求把 Booth 乘法全过程背得特别机械,但要知道:有符号乘法可以直接在补码体系下通过加减和移位实现。
四、阵列乘法器是什么,为什么快
阵列乘法器可以理解为“把手算乘法的很多步骤用硬件并行铺开”。
手算二进制乘法时,会先产生很多部分积:
x3 x2 x1 x0
× y3 y2 y1 y0
--------------------
x × y0
x × y1 左移 1 位
x × y2 左移 2 位
x × y3 左移 3 位
--------------------
最终乘积
阵列乘法器会用与门生成部分积。例如 xi × yj 在二进制里就是:
xi AND yj
然后用一堆半加器、全加器把这些部分积加起来。
它的优势是并行度高,不用像“ALU + 移位器”那样一轮一轮循环 n 次。缺点是硬件面积大、成本高、功耗也可能更高。
考研中对阵列乘法器通常不考特别深的电路细节,重点是知道:
阵列乘法器:用大量硬件并行产生和累加部分积,速度快,硬件复杂
ALU + 移位器乘法:用少量硬件反复迭代,速度慢一些,硬件简单
软件模拟乘法:没有乘法指令,用多条指令完成,通常最慢
五、“只取低 n 位作为乘法结果”,为什么还能知道高 n 位
这个问题很关键。
题目说“只取低 n 位作为乘法结果”,并不等于硬件或者分析过程完全不知道高 n 位。这里要分清两个层面:
完整乘积:n 位 × n 位,理论上最多需要 2n 位保存
返回结果:某些指令或 C 语言表达式只保留低 n 位
也就是说,完整乘积本来是 2n 位,只是最终写回目标寄存器或函数返回值时只保留低 n 位。
例如 32 位乘法:
32 位 × 32 位 = 最多 64 位乘积
如果函数返回类型是 32 位 int 或 unsigned int,那么最终只返回低 32 位。但是在判断是否溢出时,要看真实数学乘积能不能放进 32 位。如果不能放进去,即使低 32 位存在,也说明发生了溢出。
所以“如何知道高 n 位”有三种情况:
第一种,从题目分析角度,可以直接算完整 2n 位乘积。组成原理题目通常要求从机器数和真值角度分析,不是说程序运行时一定把高 n 位返回给用户。
第二种,从硬件角度,很多乘法指令内部确实会产生 2n 位乘积,只是最后根据指令格式保存其中一部分。有些体系结构还会把高位和低位分别放到两个寄存器中。例如常见教材模型里经常默认乘积寄存器可以保存双倍字长结果。
第三种,如果某个机器真的只实现“模 2ⁿ 乘法”,只给出低 n 位,且没有额外标志位或高位寄存器,那么单靠最终低 n 位确实无法还原高 n 位。因为不同的完整乘积可能具有相同的低 n 位。
例如 8 位结果只看到:
低 8 位 = FEH
它可能来自:
00FEH
01FEH
02FEH
FFFEH
...
低 8 位相同,高 8 位可以不同。所以如果硬件完全丢弃高位且不提供任何溢出标志,运行后就不能从低 n 位唯一判断高 n 位是什么。
但考研题里问“当取低 n 位作为结果时如何判断溢出”,默认是从完整 2n 位乘积判断,或者假设硬件在产生完整乘积/部分积过程中有能力检测被舍弃的高位。
六、无符号乘法只取低 n 位时,怎么判断溢出
无符号数的 n 位范围是:
0 ~ 2ⁿ - 1
两个 n 位无符号数相乘,真实结果最多需要 2n 位。
如果完整 2n 位乘积的高 n 位全为 0,说明乘积没有超过 n 位范围,可以安全放进低 n 位。
高 n 位 = 000...000 → 无符号乘法不溢出
高 n 位 ≠ 000...000 → 无符号乘法溢出
例如 8 位无符号乘法:
20 × 10 = 200
200 可以用 8 位无符号数表示:
完整 16 位:0000 0000 1100 1000
高 8 位:0000 0000
低 8 位:1100 1000
高 8 位全 0,所以不溢出。
再如:
200 × 2 = 400
400 超过 8 位无符号范围 0 ~ 255:
完整 16 位:0000 0001 1001 0000
高 8 位:0000 0001
低 8 位:1001 0000
高 8 位不全为 0,所以无符号乘法溢出。最终若只保存低 8 位,会得到 90H = 144,但真实结果 400 的高位信息丢了。
七、有符号乘法只取低 n 位时,怎么判断溢出
有符号补码 n 位范围是:
-2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1
有符号乘法判断溢出不能简单看高 n 位是否全 0,因为负数的正确扩展高位应该是全 1。
规则是:
有符号乘法不溢出 ⇔ 完整 2n 位乘积的高 n 位,必须是低 n 位符号位的符号扩展
换句话说:
如果低 n 位的最高位是 0,说明低 n 位表示非负数,那么高 n 位应该全是 0。
高 n 位全 0,低 n 位最高位为 0 → 不溢出
如果低 n 位的最高位是 1,说明低 n 位表示负数,那么高 n 位应该全是 1。
高 n 位全 1,低 n 位最高位为 1 → 不溢出
否则就是有符号溢出。
举一个 8 位例子:
-2 × 3 = -6
8 位低位结果是:
FAH = 1111 1010
完整 16 位补码乘积应该是:
1111 1111 1111 1010
高 8 位是 1111 1111,正好是低 8 位符号位 1 的扩展,所以不溢出。
再看:
100 × 2 = 200
200 超过 8 位有符号范围 -128 ~ 127。完整 16 位是:
0000 0000 1100 1000
低 8 位是:
1100 1000
低 8 位最高位是 1,按 8 位补码会解释成负数 -56。如果它真的是一个合法的 8 位负数结果,那么高 8 位应该全为 1,但现在高 8 位是全 0。
高 8 位 = 0000 0000
低 8 位符号位 = 1
不符合符号扩展 → 有符号溢出
所以本题第 04 题里:
n = 32
x = 2³¹ - 1 = 7FFFFFFFH
y = 2
完整 64 位乘积:
00000000 FFFFFFFE
对无符号乘法:
高 32 位 = 00000000
高 32 位全 0,所以无符号结果放入 32 位不溢出。
对有符号乘法:
低 32 位 = FFFFFFFE
低 32 位符号位 = 1
如果它作为合法的 32 位有符号结果,64 位完整乘积的高 32 位应该是:
FFFFFFFF
但实际高 32 位是:
00000000
不符合符号扩展,所以有符号乘法溢出。
这也是这题的核心陷阱:同样的低 32 位 FFFFFFFEH,作为 unsigned 是 4294967294,没溢出;作为 signed 是 -2,但真实数学结果是 4294967294,所以 signed 溢出。
八、加减法运算器:有符号和无符号是不是可以看成同一个?
可以。对于加法和减法,核心结论就是:
有符号整数加法
无符号整数加法
有符号整数减法
无符号整数减法
底层都可以用同一个二进制加法器完成。
原因是补码体系有一个非常重要的性质:补码加减法和无符号模 2ⁿ 加减法在位级运算规则上完全一致。
比如 8 位加法器做的事情只是:
把两个 8 位二进制位串相加
保留低 8 位
产生进位标志
它不关心这两个位串是 signed 还是 unsigned。
例如:
1000 0110 + 1111 0110 = 1 0111 1100
8 位加法器只知道:
低 8 位 = 0111 1100
最高位向外有进位
至于它表示什么,要看解释方式:
unsigned: 134 + 246 = 380,低 8 位为 124,有进位
signed: -122 + (-10) = -132,低 8 位为 +124,有符号溢出
同一个加法结果,分别产生不同的“语义判断”。
对无符号加法,主要看 CF:
CF = 1 通常表示最高位产生进位,即无符号加法超过范围
对有符号加法,主要看 OF:
OF = 1 表示补码有符号溢出
判断有符号加法溢出最常用的方法是:
同号相加,结果异号 → 溢出
异号相加 → 不可能溢出
减法也可以用同一个加法器,因为:
A - B = A + (-B)
而补码里的 -B 可以通过:
B 按位取反,再加 1
实现。所以减法器通常可以设计成“加法器 + 取反控制 + 低位进位 1”。
也就是说,加法器不需要知道“这是 signed 还是 unsigned”。真正不同的是结果出来之后:
无符号减法看是否借位,常用 CF 判断
有符号减法看 OF 判断补码溢出
所以课本里的“加减法运算器”完全可以理解成同一个底层部件:同一个加法器完成位串加减,不同标志位负责不同语义解释。
九、乘除运算器是否也能像加减法一样完全视为同一个?
这里要稍微区分。
对“只取低 n 位的乘法结果”而言,有一个重要结论:
n 位乘法只看低 n 位时,有符号乘法和无符号乘法的低 n 位结果相同。
原因是低 n 位本质上都是模 2ⁿ 的乘积。
例如:
8 位下:
FEH 可以解释为 unsigned 254,也可以解释为 signed -2
如果只看低 8 位,很多时候 signed 和 unsigned 的乘积低位是一样的。
但是,如果要得到完整 2n 位乘积,高 n 位就可能不同,因为 signed 乘法需要符号扩展,unsigned 乘法需要零扩展。
比如 8 位:
FEH × 02H
如果按无符号:
254 × 2 = 508
完整 16 位 = 01FCH
如果按有符号:
-2 × 2 = -4
完整 16 位 = FFFCH
低 8 位都是:
FCH
但高 8 位不同:
无符号高 8 位 = 01H
有符号高 8 位 = FFH
所以乘法的结论是:
只要低 n 位:有符号/无符号乘法结果低位相同
要完整 2n 位:有符号/无符号乘法结果可能不同
溢出判断:有符号/无符号规则不同
这和加减法类似,但又比加减法多一层复杂性:乘法天然可能产生双倍字长结果。
十、除法为什么不能简单完全类比加法器
除法比乘法更要注意 signed 和 unsigned 的差异。
因为除法不是简单的模 2ⁿ 位级运算。加法、减法、乘法的低 n 位都和模 2ⁿ 运算关系很强,而除法会涉及商和余数, signed 和 unsigned 解释会直接改变数学意义。
比如同一串 8 位:
1111 1110
按 unsigned 是:
254
按 signed 是:
-2
那么:
254 ÷ 2 = 127
-2 ÷ 2 = -1
商完全不同。
所以除法器通常需要区分:
无符号除法:按非负整数做除法
有符号除法:先处理符号,或用补码除法规则处理,商和余数还要符合符号规则
在指令系统中,很多机器会区分 signed divide 和 unsigned divide,例如有符号除法指令、无符号除法指令。乘法也常常区分有符号乘法和无符号乘法,尤其是当结果要保留高位或双倍字长时。
因此考研里可以这样记:
加减法:底层加法器完全可共用,signed/unsigned 主要区别在标志位解释
乘法:低 n 位可共用思路,但完整 2n 位和溢出判断要区分 signed/unsigned
除法:signed/unsigned 的数学意义不同,通常需要区分处理
十一、这类题的快速做题框架
遇到这种题,先不要急着背硬件名词。先判断题目问的是哪一层。
如果问“能不能用同一个加法器实现有符号/无符号加减”,答案基本是:
能。因为底层都是二进制加法,减法转加法。
区别在解释方式和溢出标志。
如果问“无符号加减是否溢出”,重点看:
加法:最高位是否产生进位,CF
减法:是否发生借位,CF
如果问“有符号加减是否溢出”,重点看:
加法:同号相加结果异号
减法:A - B,A 和 B 异号且结果符号与 A 不同
如果问“乘法指令怎么实现”,优先按三层回答:
没有乘法指令:软件用加法、移位、循环模拟
ALU + 移位器实现:一条乘法指令内部迭代完成加法和移位
阵列乘法器实现:专用并行硬件生成和累加部分积,速度最快
如果问“只取低 n 位如何判断乘法溢出”,就看完整 2n 位乘积:
无符号:高 n 位全 0 → 不溢出;否则溢出
有符号:高 n 位是低 n 位符号位的扩展 → 不溢出;否则溢出
最后要特别记住第 04 题这种陷阱:
完整乘积 = 00000000 FFFFFFFE
unsigned:
高 32 位全 0,所以不溢出
signed:
低 32 位符号位为 1,但高 32 位不是全 1,所以溢出
这里不是“低 32 位一样,所以溢出情况一样”。恰恰相反,低位一样,但解释方式和溢出判断不同,才是这类题的考点。



