当优化关闭时,任何流行的编译器都会利用未定义的行为吗?

问题描述 投票:0回答:2

此博客声称:

  • 未定义的行为仅在高优化级别(如 -O2 或 -O3)下“发生”。
  • 如果我使用 -O0 之类的标志关闭优化,那么就没有 UB。

都是假的。我想知道是否有任何现实世界的展示可以证明这一点。

例如,

n << 1
n<0
时触发UB。对于以下功能:

void foo(int n) {
  int t = n<<1;
  if (n>=0)
    nuke();
}

编译器可以谨慎编译:

void foo(int n) {
  int t = n>=0 ? (n*2) : error("lshift negative int");
  if (n>=0)
    nuke();
}

或通常:

void foo(int n) {
  int t = n*2;
  if (n>=0)
    nuke();
}

或者积极优化它:

void foo(int n) {
  // unused
  // int t = n<<1;

  // always true, otherwise UB
  // if (n>=0)
    nuke();
}

是否有像 gcc/clang 这样的现代流行编译器以最后一种方式运行,其中某些 UB 不仅会在该语句本地导致意外行为,而且还可能被故意利用(不考虑缓冲区溢出攻击等)并污染控件即使指定了

-O0
,也可以全局流动?

简单地说,所有 UB 实际上都以某种方式在

-O0
下定义了实现吗?

==编辑==

问题不在于这些说法是否“理论上”是错误的或无意义的(因为它们确实是)。而是是否有现实世界的展示。正如 @nate-eldredge 在评论中重新表述的那样:

给定一些形式上为 UB 的代码,现实生活中的非优化编译器会产生特别令人惊讶的结果(以上述方式),即使对于知识渊博的程序员来说也是如此?

c undefined-behavior
2个回答
6
投票
Undefined behavior only "happens" at high optimization levels like -O2 or -O3. If I turn off optimizations with a flag like -O0, then there's no UB.
这是错误的,原因只有一个。 C 语言中未定义的内容在 C 标准中已定义。未定义行为意味着从C语言的角度来看,我们不知道程序将如何表现。 UB 不必以任何特定方式表达自己 - 但它仍然是 UB。

这些说法源于不了解 UB 是什么。 UB 不会“发生”。它们处于C语言级别。即使程序“运行良好”,它仍然是 UB。由于行为未定义,如果您更改编译器、编译器版本、编译器选项或在其他操作系统或硬件上运行,它可能会停止工作。


1
投票

这两种说法都是错误的

用户@O___________也在这个答案中写道

https://stackoverflow.com/a/76720573/4386427

未定义的行为是C源代码的属性。无论编译器做什么,C 源代码仍然具有未定义的行为。编译器无法改变这一点。 然后你要求一个会令人惊讶的例子(引用):

令人惊讶(以上述方式),即使对于知识渊博的程序员来说也是如此

答案一定是

这样的例子不存在

原因:“知识渊博的程序员”知道,推理具有未定义行为的代码的行为方式是没有意义的。因此,无论生成的程序做什么,“知识渊博的程序员”都不会感到惊讶。

对于“知识较少的程序员”来说,可能会有很多令人惊讶的例子。例如:

#include <stdio.h> int* foo(void) { int x; printf("%p\n", (void*)&x); return &x; } int main(void) { printf("%p\n", (void*)foo()); return 0; }

使用 gcc 12.2 我得到:

0x7ffc5981a73c (nil)

我很惊讶吗?不,代码具有未定义的行为,因此我不期望任何特定的行为。

一个没有经验的 C 程序员会感到惊讶吗?也许吧。

简单地说,所有 UB 实际上都是在 -O0 下以某种方式实现定义的吗?

没有

“实现定义的”与未定义的行为完全不同。

不需要

实现来指定它将如何处理具有未定义行为的代码。甚至允许周一做一件事,周二做另一件事,依此类推。 “实现定义的”行为是实现必须记录的行为,以便用户知道会发生什么。两种不同的实现允许做不同的事情,只要它们记录了它们所做的事情。对于具有未定义行为的代码,不需要文档。

© www.soinside.com 2019 - 2024. All rights reserved.