C++ 不同的优化级别会导致功能不同的代码吗?
我对编译器在优化时的自由感到好奇。让我们把这个问题限制在GCC和C/C++(任何版本,任何风格的标准): 根据编译代码时使用的优化级别,是否可以编写行为不同的代码C++ 不同的优化级别会导致功能不同的代码吗?,c++,c,gcc,compiler-optimization,C++,C,Gcc,Compiler Optimization,我对编译器在优化时的自由感到好奇。让我们把这个问题限制在GCC和C/C++(任何版本,任何风格的标准): 根据编译代码时使用的优化级别,是否可以编写行为不同的代码 我想在C++中的不同构造函数中打印不同的文本位,并根据复制是否被删除而得到不同(虽然我不能使这样的事情有效)。 不允许计数时钟周期。如果你有一个非GCC编译器的例子,我也很好奇,但我不能检查它。C中示例的加分:-) 编辑:示例代码应该符合标准,并且从一开始就不包含未定义的行为 编辑2:已经有一些很好的答案了!让我把赌注增加一点:代码必
<>我想在C++中的不同构造函数中打印不同的文本位,并根据复制是否被删除而得到不同(虽然我不能使这样的事情有效)。 不允许计数时钟周期。如果你有一个非GCC编译器的例子,我也很好奇,但我不能检查它。C中示例的加分:-) 编辑:示例代码应该符合标准,并且从一开始就不包含未定义的行为 编辑2:已经有一些很好的答案了!让我把赌注增加一点:代码必须构成一个格式良好的程序,并且符合标准,并且必须在每个优化级别编译成正确的、确定性的程序。(这不包括格式不正确的多线程代码中的争用条件)我也理解浮点舍入可能会受到影响,但让我们打消这个念头 我刚刚达到了800的声誉,所以我想我应该在第一个完整的例子中以50的声誉作为奖励,以符合这些条件的精神;如果涉及滥用严格的别名,则为25。(如果有人告诉我如何向其他人发送赏金。) 是否可以编写 根据具体情况,行为会有所不同 优化级别,它是编译的 用什么 仅当您触发编译器的错误时 编辑 此示例在gcc 4.5.2中的行为不同:
void foo(int i) {
foo(i+1);
}
main() {
foo(0);
}
使用-O0
编译会创建一个程序,该程序因分段错误而崩溃。使用
-O2
编译会创建一个进入无限循环的程序 今天在我的操作系统课程中得到了一些有趣的例子。
我们分析了一些软件互斥锁,这些互斥锁在优化时可能会损坏,因为编译器不知道并行执行
编译器可以对不操作依赖数据的语句重新排序。
正如我已经在并行化代码中声明的那样,这个依赖项对于编译器是隐藏的,因此它可能会中断。
我给出的示例将导致调试过程中出现一些困难,因为线程安全性被破坏,并且由于操作系统调度问题和并发访问错误,您的代码行为不可预测。浮点计算是产生差异的成熟来源。根据各个操作的顺序,可以获得更多/更少的舍入误差 不太安全的多线程代码也可能有不同的结果,这取决于内存访问的优化方式,但无论如何,这本质上是代码中的一个缺陷
正如您所提到的,当优化级别更改时,复制构造函数中的副作用可能会消失。如果有两个指向同一内存块的指针,那么
-fstrict aliasing
选项很容易导致行为的更改。这应该是无效的,但实际上是很常见的。 < P>根据标准的任何未定义的行为都可以根据优化级别(或月相)来改变它的行为。 < P>应用的C++标准的一部分是“1.9”程序执行。部分内容如下:
一致性实现需要模拟(仅)抽象机器的可观察行为,如下所述
执行格式良好的程序的一致性实现应产生与具有相同程序和相同输入的抽象机器对应实例的可能执行序列之一相同的可观察行为
抽象机器的可观察行为是它对易失性数据的读写序列以及对库I/O函数的调用
因此,是的,代码在不同的优化级别上的行为可能不同,但是(假设所有级别都生成一致的编译器),但是它们的行为不能明显不同
编辑:请允许我更正我的结论:是的,只要每个行为与标准的抽象机器的一个行为明显相同,代码在不同的优化级别上的行为可能不同。对于C,几乎所有的操作都是在抽象机器中严格定义的,只有当可观察到的结果正好是该抽象机器的结果时,才允许进行优化。我想到的该规则的例外情况:
- 未定义的行为不一定是 不同编译器之间的一致性 运行或执行错误代码
- 浮点操作可能导致 不同舍入
- 函数调用的参数可以是 以任何顺序评估
- 带有
限定符的表达式 类型可以只计算,也可以不计算 因为它们的副作用volatile
- 相同的
限定的复合文字可以折叠到一个静态内存位置,也可以不折叠到一个静态内存位置const
#include <stdio.h>
/*
$ for i in 0 1 2 3 4
do echo -n "$i: " && gcc -O$i x.c && ./a.out
done
0: 5
1: 5
2: 5
3: -1
4: -1
*/
void f(int a) {
int b;
printf("%d\n", (int)(&a-&b));
}
int main() {
f(0);
return 0;
}
#包括
/*
$0 1 2 3 4中的i
do echo-n“$i:&&gcc-O$i x.c&&./a.out
完成
0: 5
1: 5
2: 5
3: -1
4: -1
*/
空f(整数a){
int b;
printf(“%d\n”,(int)(&a-&b));
}
int main(){
f(0);
返回0;
}
好吧,通过提供一个具体的例子,我公然为赏金卖命。我将把其他人的答案和我的评论中的片段放在一起
为了在不同的优化级别上实现不同的行为,“优化级别A”应该表示gcc-O0
(我使用的是版本4.3.4,但这并不重要,我认为
#include <iostream>
struct Foo {
~Foo() { std::cout << "~Foo\n"; }
};
int main() {
Foo f = Foo();
}
~Foo
~Foo
~Foo
void p2(void);
int main() {
p2();
return 0;
}
#include <stdio.h>
char main;
void p2() {
printf("0x%x\n", main);
}
char *f1(void) { return "hello"; }
#include <stdio.h>
char *f1(void);
int main()
{
if (f1() == "hello") printf("yes\n");
else printf("no\n");
}