Appearance
题目
一个 C 语言程序在一台 32 位机器上运行。程序中定义了三个变量 x,y 和 z,其中 x 和 z 是 int 型,y 为 short 型。当 x=127,y=-9 时,执行赋值语句 z=x+y 后,x、y 和 z 的值分别是:
错因
A
y 算错了。把 -9 写成 FFF9H 的常见思路是"负数高位补 F、把 9 直接抄到最低位"——这是对负数补码的直觉式拼凑,不是真的"按位取反加 1"。正确的 16 位补码:。FFF9H 实际上代表的是 -7,根本不是 -9。z 倒是凑对了 00000076H。
B
两个错叠加:y 错成 FFF9H(同 A),z 错成 FFFF0076H(同 C)。说明既不会算 16 位补码、也不懂混合类型加法时 short 要先符号扩展到 int。
C
y 算对了 FFF7H,但 z 错了。错的根源是忘了"整型提升":以为加法只发生在 16 位上,得到低 16 位 截掉进位 = 0076H,然后再"拼"上 y 的高 16 位 FFFFH,凑成 FFFF0076H。但 C 语言规则是:short + int 时 short 先被符号扩展为 int(高 16 位补 y 的符号位 1,得 FFFFFFF7H),整个 32 位相加;最终高 16 位是加法的真实进位结果(这里是 0000H),不是直接抄 y 的高 16 位。
总解析
第一步:x、y 各自的机内表示
- (int 型,32 位)
- (short 型,16 位补码):
- 按位取反:
- 加 1:
- 所以
第二步:混合类型加法的"整型提升"规则
C 语言中 int + short 时,short 先被提升(符号扩展)为 int,再做 32 位加法:
高 16 位补 1(因为 y 是负数,符号位 = 1,向高位扩展时复制符号位)。
第三步:z = x + y 的 32 位补码加法
| 项 | 32 位十六进制 | 二进制(高 16 位 / 低 16 位) |
|---|---|---|
| x | 0000007FH | 0000 0000 0000 0000 / 0000 0000 0111 1111 |
| y(扩展后) | FFFFFFF7H | 1111 1111 1111 1111 / 1111 1111 1111 0111 |
| 和 | 100000076H | 进位 1 + 32 位 0000 0000 / 0000 0000 0111 0110 |
低 32 位结果 = 0000 0076H(最高位的进位 1 超出 32 位寄存器范围,丢弃;这是无符号视角的"溢出",但补码加法语义上 完全正确)。
第四步:核对结果
- x = 0000007FH(不变)
- y = FFF7H(不变)
- z = 0000 0076H(int,32 位)
最终答案是 D(x=0000007FH, y=FFF7H, z=00000076H)。
易错点速记:
- 16 位补码的 -9 = FFF7H,不是 FFF9H("按位取反加 1",不是"高位补 F + 低位抄绝对值")
- int + short 时 short 先符号扩展为 int,整个加法在 32 位上完成,高 16 位是加法真实结果,不能直接照抄 y 的高 16 位
- 进位丢弃在补码加法里是正常的、语义正确的——只要结果落在 int 表示范围内,就没有"溢出"问题