我很好奇编译器在优化时的自由度.让我们将这个问题限制在GCC和C/C++(任何版本,任何标准版本):
是否有可能根据编译的优化级别编写行为不同的代码?
我想到的例子是在C++中的各种构造函数中打印不同的文本位,并根据副本是否被删除而获得差异(尽管我无法使这样的东西工作).
不允许计数时钟周期.如果你有一个非GCC编译器的例子,我也很好奇,但我无法检查它.C中的示例的奖励积分:-)
编辑:示例代码应该是标准兼容的,并且从一开始就不包含未定义的行为.
编辑2:已经有了一些很棒的答案!让我稍微了解一下:代码必须构成一个格式良好的程序并且符合标准,并且必须在每个优化级别编译为正确的,确定性的程序.(这不包括形状不规则的多线程代码中的竞争条件等.)我也理解浮点舍入可能会受到影响,但让我们对此进行折扣.
我只获得了800点声望,所以我认为我将在第一个完整的例子中赢得50点声望以符合这些条件的(精神); 25如果涉及滥用严格别名.(视某人向我展示如何向他人发送赏金.)
可以优化编译器删除无限循环,这不会改变任何数据,如
while(1)
/* noop */;
Run Code Online (Sandbox Code Playgroud)
从分析编译器可以推导出的数据流图,这样的循环是"死代码"而没有任何副作用.
是否删除了C90/C99标准禁止的无限循环?
C90或C99标准是否允许编译器删除此类循环?
更新:"Microsoft C版本6.0基本上做了这个优化.",请参阅caf的链接.
label: goto label;
return 0;
Run Code Online (Sandbox Code Playgroud)
将转变为
return 0;
Run Code Online (Sandbox Code Playgroud) c compiler-construction optimization standards infinite-loop
据说无限循环for(;;);是未定义的行为.
来自http://en.cppreference.com/w/cpp/language/memory_model
在有效的C++程序中,每个线程最终都会执行以下操作之一:
- 终止
- 调用I/O库函数
- 读取或修改易失性对象
- 执行原子操作或同步操作
没有执行任何这些可观察的行为,任何执行线程都不能永远执行.
请注意,这意味着具有无限递归或无限循环的程序(无论是作为for语句实现还是通过循环goto或其他方式)具有未定义的行为.
但是如果它在共享库中调用函数呢?
for(;;) sofunc();
该函数可以执行任何类型的阻塞I/O或抛出异常.
在这种情况下,编译器是否假定循环具有一些可观察的行为?
我看了一下C++ 0x标准草案,据我所知,堆栈溢出没有任何内容.搜索"堆栈溢出"不会产生任何结果,并且搜索"堆栈"我只获得了堆栈展开和std :: stack的引用.这是否意味着没有符合C++标准的实现,因为当本地对象(例如巨大的本地数组)耗尽内存时,没有机制允许处理错误?
这个问题的答案表明,至少C标准没有提到堆栈溢出.
要使问题具体,请考虑此计划
// Program A
int identity(int a) {
if (a == 0)
return 0;
char hugeArray[1024 * 1024 * 1024]; // 1 GB
return identity(a - 1) + 1;
}
int main() {
return f(1024 * 1024 * 1024);
}
Run Code Online (Sandbox Code Playgroud)
和这个程序
// program B
int main() {
return 1024 * 1024 * 1024;
}
Run Code Online (Sandbox Code Playgroud)
我认为C++标准不允许任何C++实现在这两个程序上做一些明显不同的事情.实际上程序A不会在任何现代机器上运行,因为它在堆栈上分配了一个exabyte内存(想象一下该函数实际上使用了巨大的数组,因此编译器无法以静默方式将其删除而不会产生不良影响).C++标准是否允许程序A失败?
编辑:问题不在于标准是否应该定义堆栈溢出会发生什么,问题是它说什么,如果有的话.