有符号数转无符号数是按位重解释而非取绝对值;如int x = -1赋值给unsigned int y,y为4294967295;同宽转换明确定义,但隐式转换易引发逻辑错误。

直接赋值会发生什么
有符号数转无符号数在 C++ 中默认是按位重解释(bitwise reinterpret),不是数学意义上的“取绝对值”或“清符号位”。int 赋给 unsigned int 时,编译器不检查值是否为负,而是把内存中的二进制模式原样挪过去,再按无符号规则解读。
例如:int x = -1; 在 32 位系统中二进制是 0xFFFFFFFF,赋给 unsigned int y = x; 后,y 的值就是 4294967295(即 2^32 - 1)。
这种转换是标准定义的、可预测的(见 ISO/IEC 14882 §7.6),但容易误以为“出错了”——其实没报错,只是语义变了。
什么时候会触发未定义行为
只有当目标类型无法表示源值时,且转换涉及整数提升以外的截断(比如从 long long 到 unsigned short),才可能因实现定义而行为不一致;但对同宽或更宽的无符号类型(如 int → unsigned int),转换始终是明确定义的模运算。
立即学习“C++免费学习笔记(深入)”;
真正危险的是隐式转换配合比较或算术:
if (x :这里 <code>x(int)会被提升为unsigned int,负数变成大正数,条件恒为假-
unsigned int u = -5; if (u > 10):成立,因为u实际是极大值 - 用
size_t接收vector::size()没问题,但拿它和-1比较就掉坑里了
显式转换的写法与取舍
推荐用 static_cast 明确表达意图,避免隐式转换带来的静默语义偏移:
int x = -42; unsigned int u = static_cast<unsigned int>(x); // 清晰,且禁用隐式转换警告
不建议用 C 风格 (unsigned int)x 或函数式 unsigned int(x),前者易被宏污染,后者在模板中可能意外调用构造函数。
如果真想“安全地转非负数”,得自己加逻辑:
int x = -42; unsigned int u = (x < 0) ? 0 : static_cast<unsigned int>(x); // 截断为 0
或者用 std::max(0, x) 再转,但要注意 std::max 返回类型仍是 int,仍需一次 static_cast。
跨平台宽度差异带来的隐患
int 和 unsigned int 在不同平台都是同宽的(通常 32 位),但 long 就不一定:Windows 上是 32 位,Linux x86_64 是 64 位。若代码写 long x = -1; unsigned long u = x;,在 Windows 和 Linux 上结果一样(都是全 1),但若换成 long long → unsigned int,就会发生截断,高位丢失。
关键点:
- 优先使用固定宽度类型(
int32_t/uint32_t)做跨平台转换 - 避免依赖
sizeof(int) == sizeof(unsigned int)—— 它成立,但sizeof(long) == sizeof(unsigned long)不一定可靠 - Clang/GCC 加
-Wsign-conversion可捕获隐式有/无符号转换,强烈建议开启
最常被忽略的不是转换本身,而是后续用这个无符号数参与减法或循环计数——比如 for (unsigned i = container.size() - 1; i >= 0; --i),i >= 0 永远为真,导致无限循环。


















