有符号数与无符号数的转换

核心思想

有符号数与无符号数之间的转换遵循一个基本原则:位模式不变,解读方式改变。硬件不做任何位级别的修改,仅改变对同一组比特位的解释方式。

转换规则

无符号数 → 有符号数(补码)

,则转换后数值不变;否则转换后的值为

有符号数 → 无符号数

,则转换后数值不变;否则转换后的值为

图示关系

无符号数范围:  0  ---------- 2^{w-1} ------------- 2^w - 1
                |                |                    |
                |                ↓                    |
有符号数范围: TMin ---------- 0 ---------- TMax      |
                |           (对应 2^{w-1})            |
                ↓                                     ↓
              负数部分映射到                    正数部分数值保持不变
              高端的无符号数区域

例如,8位下:

  • -1(有符号)→ 255(无符号)——位模式均为 11111111
  • 128(无符号)→ -128(有符号)——位模式均为 10000000

隐式转换的陷阱(重要!)

C语言中,当有符号数和无符号数出现在同一个表达式中时,有符号数会隐式转换为无符号数。这是许多难以发现的bug的根源。

典型Bug:死循环

for (size_t i = n - 1; i >= 0; i--) {  // size_t 是无符号类型
    // ...
}

i 减到 0 后再减 1 会变成最大的正数(因为无符号数下溢),导致死循环。

典型Bug:比较操作

int a = -1;
unsigned int b = 0;
if (a < b) {
    // 这里的判断不成立!因为 -1 被隐式转换为 UINT_MAX
}

最佳实践

  • 尽量避免在有符号数和无符号数之间进行比较和运算
  • 使用 -Wsign-compare 等编译选项来检测此类问题
  • 循环变量递减时注意0的边界情况

相关笔记

链接到