必须包含并使用std::isnan;它支持float/double/long double重载,不可用==判断NaN,禁用-ffast-math,非浮点类型会编译失败,嵌入式环境需手动比特位判断。

std::isnan 能直接用,但头文件和命名空间容易漏
std::isnan 是 C++11 起标准库提供的函数,用来检测一个浮点数是否为 NaN(Not a Number)。但它不在 或 的“默认可见”范围内——很多人写了 isnan(x) 却没加 std:: 前缀,或没包含正确头文件,结果编译失败或调用到 C 版本的 isnan(行为不一致)。
必须显式包含 ,并使用 std::isnan:
#include#include double x = std::nan(""); if (std::isnan(x)) { std::cout << "x is NaN\n"; }
- 不要只写
isnan(x):C++ 标准不保证它在全局命名空间中可用 - 不要用
:那是 C 头文件,可能引入宏而非重载函数,对float/long double参数行为不可靠 -
std::isnan有重载版本,支持float、double、long double,自动匹配类型
NaN 不等于任何值,包括它自己 —— 所以不能用 == 判断
这是最常踩的坑:有人写 if (x == x) 来“反向判断” NaN,逻辑没错,但可读性差、意图模糊,且容易被优化器或静态分析工具误报。更糟的是,有人真写 if (x == std::nan("")),这永远为 false —— 因为所有 NaN 都不相等。
- NaN 的 IEEE 754 定义决定了:
x == x为 false 当且仅当x是 NaN(前提是未开启 -ffast-math 等破坏 IEEE 语义的编译选项) - 但
std::isnan(x)是语义明确、意图清晰、且被编译器充分优化的标准方式 - 禁用
-ffast-math:该选项可能让std::isnan返回错误结果,或让x != x优化掉
std::isnan 对非浮点类型会编译失败,别传 int 或指针
std::isnan 只接受浮点类型。如果误传 int、bool、自定义类或空指针,编译器会报错,典型信息如:no matching function for call to 'isnan(int)'。
立即学习“C++免费学习笔记(深入)”;
- 常见误用:从 JSON 或文本解析出“数值”后没做类型检查,直接喂给
std::isnan - 若变量是
auto推导,确认它确实是double等浮点类型,而不是int(比如auto x = 0;是int) - 需要统一处理混合类型?先用
std::is_floating_point_v静态断言或 SFINAE 保护
某些平台或旧编译器不完全支持 std::isnan(尤其嵌入式)
像 MSVC 2013 以前、部分 ARM GCC 工具链、或裸机环境(no libc),std::isnan 可能缺失或返回错误。这时得回退到比特位判断。
IEEE 754 双精度 NaN 的特征是:指数全 1(11 个 1),尾数非零。安全的手动判断方式:
bool isnan_manual(double x) {
static_assert(sizeof(double) == sizeof(uint64_t), "");
uint64_t bits;
std::memcpy(&bits, &x, sizeof(bits));
return ((bits & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL) &&
((bits & 0x000FFFFFFFFFFFFFULL) != 0);
}
- 别用联合体(union)做类型双关:C++17 起属于未定义行为
- 用
std::memcpy是标准允许的“合法双关”方式 - 注意大小端不影响该判断,因为我们在操作整数视图下的原始比特
真正跨平台健壮的代码,往往得在构建时探测 std::isnan 是否可用,再决定用标准版还是手动版 —— 这点容易被忽略,尤其当项目要跑在 DSP 或 RTOS 上时。










