移位算子与-O2和不带的不同行为

时间:2011-03-04 15:29:07

标签: c++ gcc 64-bit compiler-optimization strict-aliasing

没有-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;
}

3 个答案:

答案 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得到了相同的结果。

程序的行为未定义,因为它违反了严格的别名规则。