Ker*_* SB 44 c c++ gcc compiler-optimization
我很好奇编译器在优化时的自由度.让我们将这个问题限制在GCC和C/C++(任何版本,任何标准版本):
是否有可能根据编译的优化级别编写行为不同的代码?
我想到的例子是在C++中的各种构造函数中打印不同的文本位,并根据副本是否被删除而获得差异(尽管我无法使这样的东西工作).
不允许计数时钟周期.如果你有一个非GCC编译器的例子,我也很好奇,但我无法检查它.C中的示例的奖励积分:-)
编辑:示例代码应该是标准兼容的,并且从一开始就不包含未定义的行为.
编辑2:已经有了一些很棒的答案!让我稍微了解一下:代码必须构成一个格式良好的程序并且符合标准,并且必须在每个优化级别编译为正确的,确定性的程序.(这不包括形状不规则的多线程代码中的竞争条件等.)我也理解浮点舍入可能会受到影响,但让我们对此进行折扣.
我只获得了800点声望,所以我认为我将在第一个完整的例子中赢得50点声望以符合这些条件的(精神); 25如果涉及滥用严格别名.(视某人向我展示如何向他人发送赏金.)
Rob*_*obᵩ 19
适用的C++标准部分是§1.9"程序执行".它的部分内容如下:
符合实现需要模拟(仅)抽象机器的可观察行为,如下所述....
执行格式良好的程序的一致实现应该产生与具有相同程序和相同输入的抽象机的相应实例的可能执行序列之一相同的可观察行为....
抽象机器的可观察行为是它对易失性数据的读写顺序以及对库I/O函数的调用....
所以,是的,代码在不同的优化级别上可能表现不同,但(假设所有级别都产生一致的编译器),但它们的行为不能明显不同.
编辑:请允许我更正我的结论:是的,只要每个行为与标准抽象机器的行为之一明显相同,代码在不同的优化级别上的行为可能会有所不同.
BЈо*_*вић 15
是否有可能根据编译的优化级别编写行为不同的代码?
只有当你触发编译器的bug时.
编辑
此示例在gcc 4.5.2上的行为有所不同:
void foo(int i) {
foo(i+1);
}
main() {
foo(0);
}
Run Code Online (Sandbox Code Playgroud)
编译时-O0创建一个程序崩溃与分段错误.
编译时-O2会创建一个进入无限循环的程序.
Den*_*ose 13
浮点计算是差异的成熟来源.根据各个操作的排序方式,您可以获得更多/更少的舍入错误.
根据内存访问的优化方式,不太安全的多线程代码也可能有不同的结果,但无论如何,这基本上都是代码中的错误.
正如您所提到的,当优化级别发生变化时,复制构造函数中的副作用可能会消失.
Ste*_*sop 10
好吧,通过提供一个具体的例子,我公然为赏金做游戏.我会把其他人的答案和我的评论放在一起.
出于不同优化级别的不同行为的目的,"优化级别A"应表示gcc -O0(我使用的是版本4.3.4,但它并不重要,我认为任何甚至模糊的最新版本都会显示我的差异之后),"优化级别B"应表示gcc -O0 -fno-elide-constructors.
代码很简单:
#include <iostream>
struct Foo {
~Foo() { std::cout << "~Foo\n"; }
};
int main() {
Foo f = Foo();
}
Run Code Online (Sandbox Code Playgroud)
优化级别A的输出:
~Foo
Run Code Online (Sandbox Code Playgroud)
优化级别B的输出:
~Foo
~Foo
Run Code Online (Sandbox Code Playgroud)
代码完全合法,但由于复制构造函数elision,输出依赖于实现,特别是它对禁用复制ctor elision的gcc优化标志敏感.
请注意,一般而言,"优化"是指编译器转换,它可以更改未定义,未指定或实现定义的行为,但不会更改标准定义的行为.因此,满足您的标准的任何示例都必须是一个程序,其输出未指定或实现定义.在这种情况下,标准没有指明复制ctors是否被省略,我恰好幸运的是GCC在允许的情况下可靠地消除了它们,但是可以选择禁用它.
对于C,几乎所有操作都在抽象机器中严格定义,并且只有在可观察结果与该抽象机器完全相同时才允许进行优化.想到的那条规则的例外情况:
volatile限定类型的表达式可能会或可能不会仅因其副作用而被评估const合格复合文字可能会或可能不会折叠到一个静态内存位置根据标准,任何未定义行为都可以根据优化级别(或月相)改变其行为。
| 归档时间: |
|
| 查看次数: |
4456 次 |
| 最近记录: |