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

当我编译并运行此代码时

#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.)

我知道它在没有优化标志的情况下崩溃,因为collatzwith的调用0将导致无限递归。但是,随着-O3它返回0: 1,这是错误的。这是优化中的(已知)错误还是我遗漏了什么?

gcc/ g++(9.3.0) 不优化也崩溃,编译挂起-O3。)

编辑:只是补充一点,我不是在寻找程序挂起/失败的原因(这很清楚),而是为什么编译器显然可以自由返回一些值而程序不应返回(但进入无限循环)。

编辑 2:为什么我没有选择一个更小的例子?嗯,在这里,这给出了相同的行为

int divide(int i) {
  return i == 1 ? 1 : divide(i/2);
} 

回答

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

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

这可能是编译器错误。

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

C++ 标准说:

该实现可能假设任何线程最终都会执行以下操作之一:

  • 终止,
  • 调用库 I/O 函数,
  • 通过 volatile 泛左值执行访问,或
  • 执行同步操作或原子操作。

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

  • @fuenfundachtzig 允许编译器允许返回值的规则是前向进度规则:https://timsong-cpp.github.io/cppwp/basic.exec#intro.progress-1

以上是为什么(无限)递归在 clang(和 gcc/g++)中使用 和 w/o -O3 会给出不同的结果?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>