无符号整数溢出是C++标准定义的模2ⁿ行为,非bug;size_t反向循环易死循环因i>=0恒真,i--后变为SIZE_MAX;uint64_t归零常见于未检查边界的累加、时间差或指针偏移。

无符号整数溢出是标准定义的行为,不是bug
它不是编译器或平台的“异常”,而是C++标准明确要求的:所有无符号整数算术运算必须模 2n(n为位宽)。这意味着 uint32_t 加 1 超过 UINT32_MAX,结果就是 0;size_t 减 1 到 0 以下,结果就是 SIZE_MAX。这不是“出错了”,而是你触发了标准行为。
为什么用 size_t 写反向循环容易死循环
因为 size_t 是无符号类型,i >= 0 这个条件永远为真——它根本不可能小于 0。
- 当
i == 0时执行i--,值立刻变成SIZE_MAX(64 位下是 18446744073709551615) - 下一轮仍满足
i >= 0,继续循环 - 如果循环体里有
arr[i]访问,就会越界读写,可能崩溃或静默损坏数据
uint64_t 变成 0 的典型场景
常见于计数器、时间戳差值、指针偏移等未做边界检查的计算:
- 累加一个大数组长度时,忘了
sum += len可能超限 - 用
uint64_t t = now - start,但now (例如系统时钟被调整),结果不是负数而是巨大正数,再参与后续判断就错乱 - 做哈希或 ID 生成时,直接用
id++不校验是否已达上限
怎么避免回绕导致的逻辑错误
关键不是“防止溢出”,而是“让溢出可检测、可处理”:
立即学习“C++免费学习笔记(深入)”;
- 反向循环别用
size_t i做索引,改用带符号类型如ptrdiff_t i = static_cast<ptrdiff_t>(vec.size()) - 1</ptrdiff_t>,终止条件写i >= 0 - 涉及减法的无符号运算,先判断是否够减:
if (a >= b) { result = a - b; },而不是直接写a - b - 对关键计数器(如包序号、重传次数),用显式范围检查 + 溢出断言:
assert(val - 启用编译器溢出检查(如 Clang 的
-fsanitize=unsigned-integer-overflow)只用于开发阶段,不能依赖它上线运行
回绕本身不可怕,可怕的是把它当成“不会发生”或者“发生了也看不出”。最常被忽略的是:无符号比较和带符号比较混合时,会隐式提升为无符号,连 if (i < -1) 都可能恒假。


















