C++23中推荐使用std::add_overflow和std::sub_overflow进行安全加减,语义清晰、无副作用、支持所有整型;若不支持C++23,可用GCC/Clang的__builtin_add_overflow等内置函数;手动检查易出错,需运算前判断且注意类型提升与符号边界。
std::add_overflow 和 std::sub_overflow 做安全加减(C++23)这是目前最直接、标准且无副作用的方案,但仅限 C++23 起可用。它不依赖编译器内置函数或手动位运算,语义清晰,返回 bool 表示是否溢出,并通过输出参数写入结果。
std::add_overflow(a, b, &result),返回 true 表示溢出,此时 result 值未定义result 类型必须匹配int a = INT_MAX;
int b = 1;
int result;
if (std::add_overflow(a, b, &result)) {
// 溢出处理:例如抛异常、返回错误码、截断等
} else {
// result == INT_MIN(补码下溢出结果),但这是由函数保证的合法值,非未定义行为
}__builtin_add_overflow(GCC/Clang)在 C++23 不可用的项目中,这是最常用、高效且被广泛验证的方式。它本质是编译器生成的单条带进位指令检查,零运行时开销。
_addcarry_u32 等内联汇编或 SafeInt 库)__builtin_add_overflow(a, b, &result),语义与 std::add_overflow 一致a、b、result 类型必须完全一致(如全为 int),否则编译失败或行为未定义char、short 会先整型提升,需显式转成 int* 接收结果long x = LONG_MAX;
long y = 1L;
long sum;
if (__builtin_add_overflow(x, y, &sum)) {
// 处理溢出
}对有符号整数,不能只看结果值——因为溢出后行为是未定义的,任何基于 a + b 的比较都可能被编译器优化掉。正确做法是**在运算前判断**。
int 加法:a > 0 && b > 0 && a > INT_MAX - b 表示正溢出;a 表示负溢出
a + b (利用模运算特性),但前提是 a、b 是无符号类型,否则隐式转换可能掩盖问题
if (a + b > INT_MAX) —— 这段代码本身触发未定义行为,编译器可能直接删掉整个分支std::numeric_limits::max() 替代硬编码常量,但需确保 T 是整型且非 bool
减法可统一转为加法检查(a - b → a + (-b)),但要注意 INT_MIN - (-1) 这类情况:对有符号数,-INT_MIN 本身溢出,所以不能直接算 -b 再传给加法检查函数。
std::sub_overflow 或 __builtin_sub_overflow,它们内部已处理该 corner case__builtin_mul_overflow 是 GCC/Clang 提供的对应版本,用法一致b != 0 && a > INT_MAX 
/ b),但要小心除零和舍入误差int8_t * int8_t 结果应存入 int16_t 再判断)实际工程中,最容易被忽略的是:溢出检查本身不能成为性能瓶颈,也不应掩盖真正的逻辑错误。比如在循环计数器中频繁调用检查函数,不如改用更大类型(int64_t)或静态断言约束输入范围。而一旦选择检查,就必须覆盖所有路径——尤其是混合类型运算、模板实例化、以及从用户输入直接参与算术的边界点。