考虑
#include <iostream>
int main()
{
double a = 1.0 / 0;
double b = -1.0 / 0;
double c = 0.0 / 0;
std::cout << a << b << c; // to stop compilers from optimising out the code.
}
我一直以为 a
会是+Inf, b
会是-Inf, c
会是NaN。但我也听说过严格来说浮点除以零的行为是 未定义 的,因此上述代码不能被认为是可移植的 C++。 (这在理论上抹杀了我的百万行加代码堆栈的完整性。哎呀。)
谁是正确的?
注意我对 实现定义 很满意,但我在这里谈论的是吃猫,打喷嚏的 _未定义行为_。
原文由 Bathsheba 发布,翻译遵循 CC BY-SA 4.0 许可协议
除以零整数和浮点都是未定义的行为 [expr.mul]p4 :
虽然实现可以选择支持 附件 F ,它具有明确定义的浮点除零语义。
我们可以从这个 clang 错误报告中看到 clang sanitizer 认为 IEC 60559 浮点除以零是未定义 的,即使宏 STDC_IEC_559 已定义,它也是由系统头文件定义的,至少对于 clang 不支持 附件 F 等对于 clang 仍然是未定义的行为:
该错误报告和其他两个错误报告 UBSan: Floating point division by zero is not undefined and clang should support Annex F of ISO C (IEC 60559 / IEEE 754) 表明 gcc 在浮点除以零方面符合 附录 F .
这是 GCC wiki 中浮点数学的 gcc Semantics 的 进一步支持,这表明 -fno-signaling-nans 是默认值,与 gcc 优化选项文档 一致,该文档说:
有趣的是,clang 的 UBSan 默认在 -fsanitize=undefined 下包含 _浮点除零_,而 gcc 没有:
看到它 为 clang 而 活,为 gcc 而活。