用 std::numeric_limits 获取类型边界值最可靠,避免硬编码导致的跨平台问题;需预检加减乘运算防止未定义行为,并优先使用标准库安全转换函数。

用 std::numeric_limits 查边界值最可靠
直接硬编码 INT_MAX 或 LLONG_MIN 容易出错——类型别名可能跨平台不一致,比如 long 在 Windows 和 Linux 下位宽不同。C++ 标准库提供 std::numeric_limits 模板,能精确获取任意算术类型的上下界:
#include <limits>
static_assert(std::numeric_limits<int>::is_signed);
if (x > std::numeric_limits<int>::max()) { /* 溢出 */ }
if (x < std::numeric_limits<int>::min()) { /* 下溢 */ }-
std::numeric_limits<T>::min()对有符号类型返回负最大值(如-2147483648),对无符号类型返回0 -
std::numeric_limits<T>::lowest()才是“最小可表示值”,对浮点数和有符号整数都返回真正下界(如float的-3.40282e+38) - 编译期可用:配合
constexpr或static_assert做类型安全检查
加减乘前必须先做范围预检
运行时做 a + b > std::numeric_limits<int>::max() 是错的——加法本身已触发未定义行为(UB),结果不可预测。正确做法是提前判断是否“会溢出”:
// 安全加法(int 版)
bool safe_add(int a, int b, int& result) {
if (b > 0 && a > std::numeric_limits<int>::max() - b) return false;
if (b < 0 && a < std::numeric_limits<int>::min() - b) return false;
result = a + b;
return true;
}- 乘法更危险:
a * b需拆成四象限判断(正×正、正×负、负×正、负×负),推荐用<safe_numerics>库或编译器内置函数 - Clang/GCC 提供
__builtin_add_overflow等内建函数,比手动判断快且支持所有整型宽度 - 不要依赖
std::is_same_v<decltype(a+b), int>——类型推导不等于值域安全
读取字符串转数值时,std::stoi 等函数自带溢出检测
从用户输入或配置文件解析数字时,别用 atoi——它遇到溢出只返回 INT_MAX 或 INT_MIN,无法区分“真值”和“错误”。标准库函数抛异常或设标志:
try {
int x = std::stoi("999999999999"); // 抛 std::out_of_range
} catch (const std::out_of_range&) {
// 处理溢出
}
// 或用 strtol,检查 errno 和 endptr
char* end;
errno = 0;
long x = std::strtol(s.c_str(), &end, 10);
if (errno == ERANGE || *end != '\0') { /* 错误 */ }-
std::stoi/std::stol在溢出时抛std::out_of_range,不是std::invalid_argument - 用
strtol更可控:能跳过空格、识别进制、定位非法字符位置 - 注意
std::stof等浮点函数溢出返回±inf,需用std::isinf检查,不抛异常
自定义类型或大数运算,靠断言和调试器抓隐式溢出
自己写的固定点数、分数类或用 boost::multiprecision 时,编译器不会帮你检查中间步骤。关键路径加 assert,并开启 UBSan:
立即学习“C++免费学习笔记(深入)”;
// 编译时加 -fsanitize=undefined int a = 2147483647; int b = 1; int c = a + b; // UBSan 会在运行时报错:signed integer overflow
- Release 模式下
assert失效,需用if (debug_mode) { ... }手动包裹检查逻辑 - 浮点数比较范围要小心:
std::numeric_limits<double>::max()是最大有限值,但1e308 * 10会直接变成inf,不报错 - 模板元编程中用
std::numeric_limits<T>::digits判断二进制位数,比sizeof(T)更准确(例如char可能有填充位)
最常被忽略的是:无符号整数溢出是定义良好的(自动回绕),但人脑习惯把它当错误;而有符号溢出是未定义行为——同一段代码在不同优化级别下可能产生完全不同的结果。


















