C++ constexpr表达式编译期浮点除零的编译器行为合规性问询
C++ constexpr 浮点除零行为的标准解释
基础规则说明
首先明确C++标准的两个核心规定:
- 常量表达式(
constexpr表达式)的求值过程中如果出现未定义行为,程序属于 病态格式(ill-formed),编译器必须输出诊断信息,即可直接拒绝编译。 - 浮点数除以零的行为是否属于未定义,由实现是否支持IEC 60559(IEEE 754)浮点数标准决定:
- 若实现不支持IEEE 754:浮点数除零属于未定义行为
- 若实现支持IEEE 754:非零数除以零得到对应符号的无穷大,零除以零得到NaN,行为明确定义
示例代码说明
你给出的示例代码如下:
#include <iostream> int main() { double x = 0.; // 运行时除零:所有编译器均输出 "-nan" std::cout << 0./x << std::endl; // 编译期除零:不同编译器表现不一致 constexpr double y = 0.; std::cout << 0./y << std::endl; }
附带疑问解答:运行时统一输出 -nan 是主流x86架构下浮点运算单元的默认实现选择,IEEE 754标准并未强制要求零除零得到的NaN的符号位取值,属于实现定义的范畴。
三类编译器行为的标准符合性判定
- 1、拒绝编译该程序:符合标准要求。如果编译器实现未选择支持IEEE 754,或者在常量表达式求值阶段将浮点除零判定为未定义行为,就有权直接拒绝编译该程序,MSVC的行为属于这种情况。
- 2、生成与运行时除零一致的计算结果:符合标准要求。如果编译器实现支持IEEE 754,那么编译期除零的求值结果只要符合IEEE 754的定义即可,和运行时结果一致是完全合法的,GCC的行为属于这种情况。
- 3、生成与运行时除零符号位不同的计算结果:符合标准要求。IEEE 754对零除零产生的NaN的符号位没有强制规定,属于实现定义的内容,因此编译期和运行时求值得到的NaN符号不同也是标准允许的,Clang的行为属于这种情况。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

