1、 加法溢出检测
C++ 中,对于 无符号整数加法,溢出是定义良好的行为,即发生溢出时结果会回绕到 0
(模 2^n
)。尽管不会导致程序崩溃,但在某些应用(如加密、安全、金融等)中,我们希望能显式检测溢出。
1)比较结果是否小于任一操作数
#include <iostream>
using namespace std;
// 检测无符号整数加法是否溢出
bool addWillOverflow(unsigned int a, unsigned int b) {
unsigned int result = a + b;
return result < a || result < b;
}
int main() {
unsigned int x = 4000000000;
unsigned int y = 500000000;
if (addWillOverflow(x, y)) {
std::cout << "加法发生了溢出!" << std::endl;
} else {
unsigned int sum = x + y;
std::cout << "加法没有溢出,结果是:" << sum << std::endl;
}
return 0;
}
2)使用标准库函数(C++20)
#include <limits>
#include <stdexcept>
#include <iostream>
#include <numeric> // for std::plus
using namespace std;
// 安全加法函数:检测无符号整数溢出
bool safeAdd(unsigned int a, unsigned int b, unsigned int& result) {
if (b > std::numeric_limits<unsigned int>::max() - a) {
return false; // overflow
}
result = a + b;
return true;
}
int main() {
unsigned int x = 4000000000;
unsigned int y = 500000000;
unsigned int sum = 0;
if (safeAdd(x, y, sum)) {
std::cout << "加法成功,结果为: " << sum << std::endl;
} else {
std::cout << "加法溢出,未能计算结果!" << std::endl;
}
return 0;
}
2、乘法溢出检测
C++ 中,无符号整数(如 unsigned int
, uint32_t
, uint64_t
等)的 乘法溢出 是 定义良好行为,即它会回绕(wrap around)到 0 开始。但如希望检测是否发生了溢出,可以使用以下几种方法。
1)通过除法反推判断是否溢出
#include <iostream>
#include <limits>
using namespace std;
bool mulWillOverflow(unsigned int a,
unsigned int b) {
// 乘零不会溢出
if (a == 0 || b == 0) return false;
return a > std::numeric_limits
<unsigned int>::max() / b;
}
int main() {
unsigned int a = 100000;
unsigned int b = 50000;
if (mulWillOverflow(a, b)) {
std::cout << "溢出检测:乘法将发生溢出\n";
} else {
unsigned int result = a * b;
std::cout << "结果:" << result << std::endl;
}
return 0;
}
2)使用 GCC / Clang 内建函数
#include <iostream>
using namespace std;
bool safeMul(unsigned int a, unsigned int b, unsigned int& result) {
return __builtin_umul_overflow(a, b, &result);
}
int main() {
unsigned int a = 100000;
unsigned int b = 50000;
unsigned int result;
if (safeMul(a, b, result)) {
std::cout << "乘法发生了溢出\n";
} else {
std::cout << "乘积是:" << result << std::endl;
}
return 0;
}