Appearance
题目
考虑以下 C 语言代码:
c
unsigned short usi = 65535;
short si = usi;执行上述程序段后,si 的值是( )。
错因
B
把 0xFFFF 当成了 -32767 的补码。但 -32767 的 16 位补码是 1000_0000_0000_0001 = 0x8001,不是 1111_1111_1111_1111 = 0xFFFF。混淆了"全 1" 和"最高位 1 + 末位 1"两种位模式。
C
误以为 0xFFFF(全 1)是 short 类型的"最小负数"。但 16 位补码的最小负数是 -32768 = 1000_0000_0000_0000 = 0x8000,特征是"只有最高位为 1",不是"全 1"。最小负数和 -1 在位模式上完全不同。
D
以为转换会"保留 65535 的数值"。但 short 的范围是 [-32768, 32767],根本装不下 65535;同样地,-65535 也超出 short 范围。C 语言的 unsigned → signed 转换是按位重新解读(位模式不变,按目标类型的编码规则解释),不是数值意义上的"保留"。
总解析
第一步:写出 65535 的 16 位无符号表示
$65535 = 2^{16} - 1 = $ 1111 1111 1111 1111 (16 个 1) = 0xFFFF
第二步:把这个位模式赋给 si(位模式不变,按 short 补码重新解读)
C 标准规定:同宽度的有符号 ↔ 无符号转换位模式不变,只是按目标类型重新解读。所以 si 的内存内容也是 1111 1111 1111 1111。
第三步:把 1111 1111 1111 1111 当 16 位补码读
最高位 1 → 负数。求绝对值("取反加 1"):
| 步骤 | 二进制 |
|---|---|
| 原 | 1111 1111 1111 1111 |
| 取反 | 0000 0000 0000 0000 |
| +1 | 0000 0000 0000 0001 |
绝对值 = 1 → si = -1。
最终答案是 A(-1)。
位模式 → 真值 速查(16 位补码典型值):
| 位模式 | 十六进制 | 当 short(补码) | 当 unsigned short |
|---|---|---|---|
0000...0000 | 0x0000 | 0 | 0 |
0000...0001 | 0x0001 | 1 | 1 |
0111...1111 | 0x7FFF | +32767(最大正) | 32767 |
1000...0000 | 0x8000 | -32768(最小负) | 32768 |
1000...0001 | 0x8001 | -32767 | 32769 |
1111...1111 | 0xFFFF | -1 | 65535 |
通用规律:unsigned short → short 时,
本题 usi = 65535 → si = 65535 - 65536 = -1 ✓ 与上面位模式推导一致。
易错点速查:
- 0xFFFF(全 1)= -1,不是 -32767 也不是 -32768
- 0x8000(只高位 1)= -32768(最小负)
- unsigned → signed 是按位重新解读,不是数值变换;超出范围 ≠ 报错