开启STDC FENV_ACCESS时信号NaN强转float是否触发FE_INVALID异常
问题背景
当f为信号NaN(signaling NaN)时,在开启#pragma STDC FENV_ACCESS ON的前提下,执行(float)f强制类型转换是否会触发FE_INVALID浮点异常?
测试代码与运行情况
示例代码(t0.c)
#include <stdio.h> #include <stdint.h> #include <fenv.h> #pragma STDC FENV_ACCESS ON void print_fe_excepts_raised(void) { printf("exceptions raised"); if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO"); if (fetestexcept(FE_INEXACT)) printf(" FE_INEXACT"); if (fetestexcept(FE_INVALID)) printf(" FE_INVALID"); if (fetestexcept(FE_OVERFLOW)) printf(" FE_OVERFLOW"); if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW"); if (fetestexcept(FE_ALL_EXCEPT)==0) printf(" none"); printf("\n"); } int main(void) { union { uint32_t u; float f; } snan = { .u = 0x7FA00000 }; snan.f = (float)snan.f; print_fe_excepts_raised(); return 0; }
编译命令(x86_64 Linux环境,使用clang trunk编译器)
$ clang t0.c -std=c11 -pedantic -Wall -Wextra -ffp-model=strict -lm
编译无输出。
运行结果
$ ./a.out exceptions raised none
疑问
是否应当打印输出exceptions raised FE_INVALID?
回答
是,按标准该场景下应当触发FE_INVALID异常,该运行结果不符合标准要求,是clang的已知未修复问题,具体说明如下:
- 规范要求
C11标准5.1.2.3节明确规定,对信号NaN执行算术操作时需要触发FE_INVALID异常,同类型浮点强制转换属于会触发NaN信号的算术操作范畴。IEEE 754-2008规范也规定,除明确标注为静默的操作外,任何访问信号NaN的算术运算都需要抛出无效操作异常。
- 测试代码无逻辑错误
- 已正确开启
STDC FENV_ACCESS ON,使用-ffp-model=strict开启严格浮点模型,构造的0x7FA00000确实是标准的单精度信号NaN - 此处的
(float)snan.f同类型转换不属于无副作用的类型转换,按标准应当触发信号NaN的异常检查
- 无异常输出的原因
clang在处理同类型浮点强制转换时会默认将该操作优化为空操作,哪怕开启严格浮点模型也没有插入检查信号NaN的指令,属于已知bug。更换为gcc编译测试同一份代码,会正确输出exceptions raised FE_INVALID。
内容的提问来源于stack exchange,提问作者pmor
相关产品推荐
相关产品推荐

