Appearance
题目
假定在一个 8 位字长的计算机中运行如下 C 程序段:
c
unsigned int x=134;
unsigned int y=246;
int m=x;
int n=y;
unsigned int z1=x-y;
unsigned int z2=x+y;
int k1=m-n;
int k2=m+n;若编译器编译时将 8 个 8 位寄存器 R1~R8 分别分配给变量 x、y、m、n、z1、z2、k1 和 k2。请回答下列问题。(提示:带符号整数用补码表示)
(1) 执行上述程序段后,寄存器 R1、R5 和 R6 的内容分别是什么(用十六进制表示)?
(2) 执行上述程序段后,变量 m 和 k1 的值分别是多少(用十进制表示)?
(3) 上述程序段涉及带符号整数加/减、无符号整数加/减运算,这四种运算能否利用同一个加法器及辅助电路实现?简述理由。
(4) 计算机内部如何判断带符号整数加/减运算的结果是否发生溢出?上述程序段中,哪些带符号整数运算语句的执行结果会发生溢出?
解析
本题考查的核心思想:位模式相同,"解释"不同——同一组 8 比特,作无符号读是 134,作带符号补码读就是 −122。理解这一点,4 个子问题就贯通了:
- 加法器只做"模 的加法",不区分有符号 / 无符号;
- 减法靠"加上被减数的补码"实现;
- 溢出概念只对带符号有效,进位(Carry)才是无符号越界的标志。
记 ,。
(1) R1、R5、R6 的内容 [3 分]
R1 = x = 134。 直接转十六进制:
R5 = z1 = x − y(无符号减法)。
8 位加法器没有"减法电路",减法用补数法:。
先算 的 8 位补码:。再做 8 位加法:
1000 0110 (x = 134)
+ 0000 1010 (-y mod 256 = 10)
-----------
(0)1001 0000 Cout = 0R5 = 1001 0000B = 90H(十进制 144,即 )。
R6 = z2 = x + y(无符号加法)。
1000 0110 (x = 134)
+ 1111 0110 (y = 246)
-----------
(1)0111 1100 Cout = 1R6 = 0111 1100B = 7CH(十进制 124,即 ,加法器丢掉的 Cout 是越界标志)。
(2) m 与 k1 的值 [2 分]
int m = x; 在汇编层面只是寄存器对寄存器的拷贝,位模式不变,只换"解释规则"——把 86H 当补码读。
算 m。 R3(= m)= 1000 0110B,最高位 1 → 负数。求其绝对值(取反加 1):
所以 。
算 k1。 R7(= k1)= R5 的位模式 = 1001 0000B,最高位 1 → 负数:
所以 。
易错点: 同一个 86H 当无符号是 134,当补码是 −122。区别在"如何解读最高位":无符号把它当 的位权,补码把它当 的位权。
(3) 同一加法器能否实现 4 种运算?[3 分]
能。 一个 n 位加法器物理上只完成 "模 的二进制加法",它根本不区分输入是无符号还是补码。
| 运算 | 加法器实际计算 | 结果解释方式 |
|---|---|---|
| 无符号加 | 当无符号读 | |
| 无符号减 | 当无符号读 | |
| 带符号加 | 当补码读 | |
| 带符号减 | 当补码读 |
只要在加法器外配一组 取反 + 末位 +1 的控制电路(用于生成 ),就能让同一个加法器复用于全部 4 种运算。这正是补码设计的核心动机:让加减运算硬件统一。
(4) 溢出判断与本题中的溢出语句 [4 分]
判断规则(仅对带符号运算有意义):
- 符号判别法:两个加数符号相同,但结果符号与之不同 → 溢出;
- 进位异或法:最高位进位 与次高位进位 不同(即 )→ 溢出。
减法 等价于做加法 ,仍套上述规则。无符号运算没有"溢出"概念,越界只产生 进位标志 CF。
逐条排查 4 条赋值/算式:
| 语句 | 类型 | m / n / 结果(十进制) | 是否溢出 |
|---|---|---|---|
int m = x; | 赋值 | / | |
int n = y; | 赋值 | / | |
unsigned z1 = x - y; | 无符号减 | 不适用(产生借位) | |
unsigned z2 = x + y; | 无符号加 | 不适用(产生进位) | |
int k1 = m - n; | 带符号减 | ✗(在 内) | |
int k2 = m + n; | 带符号加 | ✓ 溢出(小于 ) |
用进位异或法复核 k2:
1000 0110 + 1111 0110 的逐位加法(参见 (1) 中 z2 的列式)得 0111 1100B,最高位进位 ,次高位进位 , → 溢出。
用符号法复核 k2: 两个加数符号都是 1(负),结果符号是 0(正),符号反转 → 溢出。
易错点 1: 别说"无符号溢出"。规范术语:无符号越界叫 进位(Carry),带符号越界才叫 溢出(Overflow)。CPU 用 CF(Carry Flag)记前者,用 OF(Overflow Flag)记后者。
易错点 2: 第 (4) 问只有最后一条 (
k2 = m + n) 溢出。k1 = m − n看起来"两个负数"很危险,但实际是 ,没出范围;不要被符号唬住——必须实际算一遍。
编者注(生僻术语): 8 位补码可表示范围 。判断带符号运算是否溢出,最稳妥就是先算十进制结果,再看落不落在这个区间。