没有-O2,此代码打印84 84
,O2标志输出为84 42
。代码是在64位Linux平台上使用gcc 4.4.3.
编译的。为什么以下代码的输出不同?
请注意,使用-Os编译时,输出为0 42
#include <iostream>
using namespace std;
int main() {
long long n = 42;
int *p = (int *)&n;
*p <<= 1;
cout << *p << " " << n << endl;
return 0;
}
答案 0 :(得分:19)
当你使用gcc进行优化时,它可以根据表达式的类型使用某些假设,以避免重复不必要的读取并允许在内存中保留变量。
您的代码具有未定义的行为,因为您将指向long long
(gcc允许作为扩展)的指针转换为指向int
的指针,然后操纵指向对象,就好像它一样是int
。指向int
的指针通常不能指向long long
类型的对象,因此允许gcc假定写入int
的操作(通过指针)不会影响类型为long long
的对象。
因此,将n
的值在最初分配的时间和随后打印的时间之间进行缓存是合法的。没有有效的写入操作可能已更改其值。
要阅读的特定开关和文档是-fstrict-aliasing
。
答案 1 :(得分:6)
你正在打破严格的别名。使用-Wall进行编译应该会给出dereferencing type-punned pointer
警告。参见例如http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
答案 2 :(得分:1)
我在Linux / i386上使用GCC 4.4.4得到了相同的结果。
程序的行为未定义,因为它违反了严格的别名规则。