无符号unsigned
无符号unsigned
这是一个非常好的问题。很多初学者(甚至有经验的程序员)容易陷入一个误区:“既然这个变量(比如年龄、身高、人数)不可能是负数,那我就应该用 unsigned。”
这个直觉通常是错的。Google 的 C++ 编码规范甚至明确建议:除非万不得已,尽量使用有符号类型(int)。
那么,到底什么时候必须或推荐使用 unsigned 呢?主要有以下三种场景:
1. 进行位操作 (Bitwise Operations) —— 最核心场景
这是使用 unsigned 最正当、最无可争议的理由。 如果你要把一个变量当作“一串二进制位”(而不是一个数字)来处理,比如进行移位操作(>>, <<)、按位与/或/异或,请务必使用 unsigned。
- 原因: 有符号数(
signed)的最高位是符号位。当你对有符号数进行右移操作时,不同的编译器处理方式不同(有的补0,有的补1),结果是未定义的或不可移植的。而无符号数的行为是确定的(总是补0)。 - IoT 场景: 你是物联网专业的,将来写嵌入式代码(比如控制寄存器、设置GPIO引脚状态)时,会大量使用
unsigned。
1 | |
2. 确实需要更大的正数范围
int(通常是32位)的最大值大约是 21亿。 unsigned int 的最大值大约是 42亿。
如果你的数据量明确会超过 21 亿,但不会超过 42 亿,那么使用 unsigned 是为了利用这多出来的一倍空间。
- 例子: 网络传输的字节数统计、系统运行的毫秒数(
uptime)、哈希算法的结果。
3. 表示内存大小、数组索引 (标准库约定)
C语言的标准库中,表示“对象大小”或“数组长度”的类型是 size_t,它本质上就是一种 unsigned 类型。
- 原因: 内存地址、数组下标、文件大小物理上不可能是负的,而且内存空间可能非常大,需要利用无符号数的全部范围。
- 场景: 使用
sizeof、strlen、memcpy时,参数和返回值都是无符号的。
⚠️ 为什么不要随便用 unsigned?(避坑指南)
除了上述情况,做普通数学运算(加减乘除、循环计数)时,**默认首选 int**。
这是因为无符号数有两个巨大的陷阱:
陷阱一:死循环风险
看下面这个想倒序遍历数组的代码:
1 | |
结果: 死循环。因为 unsigned 永远大于等于 0。
陷阱二:算术下溢 (Underflow)
如果你做减法:
1 | |
你期望 c 是 -2,但实际上 c 会变成一个巨大的正数(4294967294)。后续如果有逻辑判断 if (c < 0),就会像你刚才的阶乘程序一样,直接失效。
陷阱三:混合运算的隐式转换 (你刚才遇到的)
C语言规定,当 int 和 unsigned int 进行运算或比较时,int 会被自动强转为 unsigned int。
1 | |
总结建议
作为物联网工程的学生,你可以遵循这个简单的决策树:
- 是在操作寄存器、位掩码、二进制流吗? -> 用
unsigned。 - 是标准库要求的参数(如
malloc的大小)吗? -> 用size_t(unsigned)。 - 数值极其巨大,超过了 21 亿吗? -> 用
unsigned或long long。 - 其他所有情况(包括计数、年龄、分数、普通数学计算) -> **老老实实用
int**。哪怕变量不会是负数,用int也可以利用“溢出报错”或“变成负数”来帮你发现 Bug,而不是默默地变成一个巨大的随机数。
无符号unsigned
http://example.com/2025/12/13/无符号unsigned/