<p>正确做法是运算前检查:加法上溢需判a > 0 && b > LLONG_MAX - a,下溢需判a < 0 && b < LLONG_MIN - a;不可依赖a + b结果判断,因其触发未定义行为。</p>

直接用 long long 不解决溢出问题,它只是把溢出点往后推了一步;真正可靠的做法是:在运算前检查、用编译器内置函数捕获、或换字符串/数组存大数——选哪种,取决于你是否需要精确值、是否允许依赖扩展、以及性能敏感度。
怎么提前判断 long long 加法会溢出
不能靠 a + b 这类后验比较,因为有符号溢出是未定义行为(UB),编译器可能直接优化掉整条分支。必须前置检查。
- 加法上溢:当
b > 0且a > std::numeric_limits<long long>::max() - b</long> - 加法下溢:当
b 且 <code>a ::min() - b - 更稳妥的写法是统一用
__builtin_add_overflow(a, b, &result)(GCC/Clang),它不触发 UB,返回bool表示是否溢出 - 别用
double中转判断,double只能精确表示 ≤ 2⁵³ 的整数,而long long能到 2⁶³,中间大量值会失真
为什么 __builtin_mul_overflow 比手动检查乘法更实用
乘法的前置条件检查逻辑复杂(要分正负、零、边界),容易漏 case;而 __builtin_mul_overflow 一行就覆盖所有情况,且无运行时开销。
- 手动检查需同时处理:
a == 0、b == 0、同号/异号、是否接近边界,代码易错 -
__builtin_mul_overflow(a, b, &result)在溢出时返回true,result值未定义但不会触发 UB - 它对
unsigned long long同样有效,避免误以为“无符号就安全” - 若需跨平台,可封装一层:GCC/Clang 用 builtin,MSVC 用
Int64x64To128或退到字符串
什么时候该放弃 long long,改用字符串或数组
当你需要完整十进制结果(比如输出阶乘、验证数字各位和、做数位 DP)、或者中间结果必然超 2⁶⁴(如 10^18 * 10^18),long long 就不够用了。
立即学习“C++免费学习笔记(深入)”;
- 字符串适合输入/输出密集、逐位操作多的场景(如回文数、幸运数筛选),但加减需自己实现,效率低
- 数组(如
std::vector<uint8_t></uint8_t>存 BCD 或十进制位)比字符串省内存,也方便做进位优化 - 别用
std::string存单个数字再反复stoi—— 频繁转换开销大,且stoi本身可能抛异常或截断 - 如果只关心模意义下的结果(如快速幂取模),优先用
(a % MOD) * (b % MOD) % MOD降维,而不是硬算全量
最容易被忽略的一点:溢出检测不是写一次就完事。所有接收用户输入、读配置、计循环次数、做索引偏移的地方,只要涉及算术,都得考虑是否可能溢出——尤其是当类型从 int 换成 long long 后,开发者常误以为“安全了”,其实只是延迟暴露问题。


















