为float变量赋值NAN触发浮点异常是否属于正常合规行为?
该表现属于不符合C标准的异常行为
核心判定依据
C2x及之前的所有C标准明确规定:宏
NAN当且仅当实现支持float类型的安静NaN(quiet NaN)时才会定义,它会展开为类型为float、表示安静NaN的常量表达式。
该规定包含两个强制约束:
NAN属于编译期常量表达式,其值在编译阶段就需要确定,运行时仅执行赋值操作,不能产生任何运算相关的副作用(包括触发浮点异常)NAN是安静NaN,本身的传播、赋值操作不允许触发浮点无效异常,只有信号NaN(signaling NaN)参与运算时才会触发异常
Windows UCRT实现的违规点
UCRT头文件中把NAN定义为运行时计算的表达式:
#define NAN ((float)(INFINITY * 0.0F)) #define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF)) #define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF必须溢出
该实现存在两处违规:
- 把本该编译期确定的常量变成了运行时运算,
_HUGE_ENUF相乘溢出、INFINITY乘0的操作都会在运行时触发FE_OVERFLOW、FE_INVALID、FE_INEXACT异常,污染运行时浮点状态 - 违反了安静NaN的语义约定,让单纯的NaN赋值操作也产生了异常标记
规避方案
如果在Windows平台开发需要避免该问题,可以选择两种方案:
- 直接通过二进制构造安静NaN:
#include <stdint.h> float get_nan_f(void) { float f; // 小端平台32位安静NaN的二进制表示,大端平台需要调整字节序 *(uint32_t*)&f = 0x7FC00000U; return f; } - 调用标准库函数
nanf("")生成NaN,UCRT下该函数不会触发浮点异常
内容的提问来源于stack exchange,提问作者pmor
相关产品推荐
相关产品推荐

