Appearance
题目
在 32 位计算机上执行下列 C 语言代码:
c
short si = -32767
unsigned int ui = si;则 ui 的真值为( )。
错因
A
直接把 的"绝对值" 当成最终结果,相当于认为"赋给 unsigned 就是把负号扔掉"。这跳过了 C 语言赋值时先符号扩展再按无符号解读的全过程,把转换当成了"取绝对值"。
B
注意到了"负数转无符号要发生位串重新解读",但只在 16 位范围内做了一次:算了 。这其实是 si 自己作为 16 位位串的无符号值,忘了 si 要先扩展为 32 位 int 再转 unsigned int——扩展的高 16 位补的是符号位(1)而不是 0,所以最终的位串高 16 位全是 1,不止 16 位那么大。
C
方向对了——已经意识到结果应该是 形式的大正数,但 算成了 。常见来源:把 错当成 (与 short 最小值 混了一位),或在求补码时少加了那个 。表现就是最终结果比正确答案小 ,正负号反了的"差一"陷阱。
总解析
思路:本题考三个连续动作的组合——
-32767写进 16 位 short:补码表示short → unsigned int在 C 标准里实际分两步:先按 signed short 提升到 int(符号扩展),再把这个 int 重新解释为 unsigned int(位串不变,仅改变解读方式)- unsigned int 的真值就是这个 32 位位串按无符号解读
漏掉第 2 步的"符号扩展",几乎一定算错。
第一步:si 的 16 位补码
按 16 位补码定义 。换算成位串:
最高位是 1,确认是负数。
第二步:short → int(符号扩展提升)
C 语言里把 short 赋给 int / unsigned int 时,先把 short 按其有符号性提升为 int。si 是 signed short 且为负,高 16 位全补 1:
得到 32 位 int 位串:
按 32 位补码解读,这个值仍然是 (符号扩展不改变有符号值,这是它的定义)。
第三步:int → unsigned int(位串透传,重新解读)
赋给 unsigned int 时位串不动,只把它当无符号数读:
| 位段 | 二进制 | 贡献的真值 |
|---|---|---|
| 高 16 位 (FFFF) | ||
| 低 16 位 (8001) | ||
| 合计 | 0xFFFF8001 |
化简:。
更直观的算法:32 位补码负数 的位串,按无符号读就是 。这里 ,所以:
最终答案是 D()。
易错点速记:
| 转换方向 | 行为 | 此题对应 |
|---|---|---|
| signed short → int | 符号扩展(高位补符号位 1) | 高 16 位补 FFFF,不是 0000 |
| int → unsigned int | 位串不变,重新解读 | 0xFFFF8001 当无符号读 |
| 负数 转无符号 32 位 | 真值变成 |
口诀:signed 短转长走符号扩展,signed 转 unsigned 只换眼镜不改位。两步合起来,负数转无符号就是"接近上限的大正数",而不是 16 位范围内的小数。