c++ - 为什么(无限)递归在 clang(和 gcc/g++)中使用 和 w/o -O3 会给出不同的结果?

标签 c++ c clang compiler-optimization

当我编译并运行此代码时

#include <stdio.h>

int collatz(int a) {
    return a == 1 ? 1 : collatz((a%2) ? 3*a+1 : a/2);
}

int main() {
    for (int a = 0; a < 10; ++a)
        printf("%d: %d\n", a, collatz(a));
}
clang (10.0.0-4ubuntu1) 它崩溃了,但是当我添加 -O3 时它运行良好。 (当将此作为 C 或 C++ 代码传递给 clang 时,这两者都成立。)
我知道它在没有优化标志的情况下崩溃,因为调用了 collatz0会导致无限递归。但是,与 -O3它返回 0: 1 ,这是错误的。这是优化中的(已知)错误还是我遗漏了什么?
( gcc/g++ (9.3.0) 未优化也崩溃,编译挂起 -O3 。)
编辑:补充一点,我不是在寻找程序挂起/失败的原因(这很清楚),而是为什么编译器显然可以自由返回一些值而程序不应返回(但进入无限循环)。
编辑 2:为什么我没有选择一个更小的例子?嗯,在这里,这给出了相同的行为
int divide(int i) {
  return i == 1 ? 1 : divide(i/2);
} 

最佳答案

Is that a (known) bug in the optimization or am I missing something?


这不是优化中的错误。这是正在编译的程序中的一个错误。程序的行为在 C++ 中是未定义的。

it returns 0: 1, which is wrong


当程序的行为未定义时,没有“错误”的行为。

but the compilation hangs with -O3


这可能是编译器错误。

how can the compiler just decide to return something, whereas, if you follow the program logic, it should not.


当程序的行为未定义时,编译器可以决定做任何事情或不做任何事情。没有什么特别应该做或不应该做的。未定义的程序没有逻辑。

why the behaviour is undefined


C++ 标准说:

[intro.progress]

The implementation may assume that any thread will eventually do one of the following:

  • terminate,
  • make a call to a library I/O function,
  • perform an access through a volatile glvalue, or
  • perform a synchronization operation or an atomic operation.

如果参数为 0,线程将永远不会做任何这些事情,因此 [language] 实现被允许假设函数永远不会被参数 0 调用。当你用这样的参数调用函数时,您与此假设相矛盾,行为未定义。

关于c++ - 为什么(无限)递归在 clang(和 gcc/g++)中使用 和 w/o -O3 会给出不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68983979/

相关文章:

c++ - 模板类中重载函数的条件编译

c - MATLAB C 矩阵接口(interface) : does mxDestroyArray recursively destroy elements of cells and structs?

c++ - 获取单个文件的 Clang AST

c++ - clang 格式在 gVim 下不工作

c++ - 声明后如何获取变量及其大小?

c++ - 来自 dll 的函数调用 [表观调用括号前的表达式必须具有(指向)函数类型]

c++ delete[] 二维数组导致堆损坏

C++ - 两个类相互实例化,不能使用前向声明

c - 将数组作为参数传递给函数而不将数组的长度传递给该函数

在c中为windows编译glpk