无符号unsigned

无符号unsigned

这是一个非常好的问题。很多初学者(甚至有经验的程序员)容易陷入一个误区:“既然这个变量(比如年龄、身高、人数)不可能是负数,那我就应该用 unsigned。”

这个直觉通常是错的。Google 的 C++ 编码规范甚至明确建议:除非万不得已,尽量使用有符号类型(int)。

那么,到底什么时候必须推荐使用 unsigned 呢?主要有以下三种场景:


1. 进行位操作 (Bitwise Operations) —— 最核心场景

这是使用 unsigned 最正当、最无可争议的理由。 如果你要把一个变量当作“一串二进制位”(而不是一个数字)来处理,比如进行移位操作(>>, <<)、按位与/或/异或,请务必使用 unsigned

  • 原因: 有符号数(signed)的最高位是符号位。当你对有符号数进行右移操作时,不同的编译器处理方式不同(有的补0,有的补1),结果是未定义的或不可移植的。而无符号数的行为是确定的(总是补0)。
  • IoT 场景: 你是物联网专业的,将来写嵌入式代码(比如控制寄存器、设置GPIO引脚状态)时,会大量使用 unsigned
1
2
3
4
5
6
7
// 推荐:用于位掩码
unsigned int flags = 0xFF;
flags = flags >> 1; // 结果明确,左边补0

// 不推荐:有符号数移位可能出问题
int bad_flags = -5;
bad_flags = bad_flags >> 1; // 结果依赖编译器,极其危险

2. 确实需要更大的正数范围

int(通常是32位)的最大值大约是 21亿unsigned int 的最大值大约是 42亿

如果你的数据量明确会超过 21 亿,但不会超过 42 亿,那么使用 unsigned 是为了利用这多出来的一倍空间。

  • 例子: 网络传输的字节数统计、系统运行的毫秒数(uptime)、哈希算法的结果。

3. 表示内存大小、数组索引 (标准库约定)

C语言的标准库中,表示“对象大小”或“数组长度”的类型是 size_t,它本质上就是一种 unsigned 类型。

  • 原因: 内存地址、数组下标、文件大小物理上不可能是负的,而且内存空间可能非常大,需要利用无符号数的全部范围。
  • 场景: 使用 sizeofstrlenmemcpy 时,参数和返回值都是无符号的。

⚠️ 为什么不要随便用 unsigned?(避坑指南)

除了上述情况,做普通数学运算(加减乘除、循环计数)时,**默认首选 int**。

这是因为无符号数有两个巨大的陷阱:

陷阱一:死循环风险

看下面这个想倒序遍历数组的代码:

1
2
3
4
5
unsigned int i;
// 错误!当 i 为 0 时,i-- 变成了最大的正整数,导致 i >= 0 永远成立
for (i = 5; i >= 0; i--) {
printf("%d\n", i);
}

结果: 死循环。因为 unsigned 永远大于等于 0。

陷阱二:算术下溢 (Underflow)

如果你做减法:

1
2
3
unsigned int a = 3;
unsigned int b = 5;
unsigned int c = a - b;

你期望 c-2,但实际上 c 会变成一个巨大的正数(4294967294)。后续如果有逻辑判断 if (c < 0),就会像你刚才的阶乘程序一样,直接失效。

陷阱三:混合运算的隐式转换 (你刚才遇到的)

C语言规定,当 intunsigned int 进行运算或比较时,int 会被自动强转为 unsigned int

1
2
3
4
5
6
int a = -1;
unsigned int b = 1;
if (a > b) {
// 竟然会执行这里!因为 -1 变成了 42亿 > 1
printf("-1 is bigger than 1??");
}

总结建议

作为物联网工程的学生,你可以遵循这个简单的决策树:

  1. 是在操作寄存器、位掩码、二进制流吗? -> 用 unsigned
  2. 是标准库要求的参数(如 malloc 的大小)吗? -> 用 size_t (unsigned)。
  3. 数值极其巨大,超过了 21 亿吗? -> 用 unsignedlong long
  4. 其他所有情况(包括计数、年龄、分数、普通数学计算) -> **老老实实用 int**。哪怕变量不会是负数,用 int 也可以利用“溢出报错”或“变成负数”来帮你发现 Bug,而不是默默地变成一个巨大的随机数。

无符号unsigned
http://example.com/2025/12/13/无符号unsigned/
作者
王柏森
发布于
2025年12月13日
许可协议