NaN在不同的g ++版本中处理不同

Jas*_*siu 2 c++ floating-point gcc nan undefined-behavior

考虑以下程序,这显然是错误的:

#include <cstdio>

double test(int n) {
    if (n % 2 == 0)
        return 0.0;
    // warning: control reaches end of non-void function
}

int main() {
    printf("%.9lf\n", test(0));
    printf("%.9lf\n", test(1));
    printf("%.9lf\n", test(2));
    printf("%.9lf\n", test(3));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在32位Ubuntu 8.04上使用g ++ 4.2.4版(Ubuntu 4.2.4-1ubuntu4)编译时,它会产生以下输出:

0.000000000
nan
0.000000000
nan
Run Code Online (Sandbox Code Playgroud)

当在64位Ubuntu 10.04上使用g ++ 4.4.3版(Ubuntu 4.4.3-4ubuntu5)编译时,它会产生以下输出:

0.000000000
0.000000000
0.000000000
0.000000000
Run Code Online (Sandbox Code Playgroud)

似乎较旧的编译器为了返回NaN而不是垃圾而做了一些额外的工作,而较新的编译器只返回内存中的任何内容.究竟是什么导致了这种行为差异以及如何控制它并使其在不同的编译器版本中可预测?

编辑:很抱歉没有提及之前的未定义行为.我知道差异来自于这个程序有未定义的行为.我想知道为什么前gcc版本似乎把一些精力和产生的代码,始终返回NaN,并这种行为变为后者的gcc版本所观察到的.另外,通过"可预测",我的意思不是如何用C++编写好的程序,而是如何控制这个gcc行为(可能有一些命令行选项?).

Ale*_* C. 12

您显示的代码具有未定义的行为,因为未能test从所有控制路径返回值.

没有什么可以期待的,除了首先写一个正确的程序,你无法控制它.

编辑:我认为你不应该依赖编译器似乎做什么.

即使你认为你应该,你也不应该.

查看dissasembly将揭示这段特定代码将被编译成什么,但除了这段特定代码之外,您将无法概括为其他任何内容,尤其是在存在优化的情况下.未定义的行为实际上意味着您的想法:除非您碰巧掌握GCC的代码库,否则无法保证您观察到的内容在其他上下文中可以重现.

这里唯一明智的解决方案是使用-Wall进行编译并修复那些"并非所有返回路径都返回一个值",这样行为是1)定义的,2)由定义.