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

Leo*_*nid 8 c++ 64-bit gcc strict-aliasing compiler-optimization

没有-O2这个代码打印84 84,输出为O2标志84 42.代码是gcc 4.4.3.在64位Linux平台上编译的.为什么以下代码的输出不同?

请注意,使用-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;
}
Run Code Online (Sandbox Code Playgroud)

CB *_*ley 19

当您使用gcc进行优化时,它可以根据表达式的类型使用某些假设,以避免重复不必要的读取并允许在内存中保留变量.

您的代码具有未定义的行为,因为您将一个指针long long(一个gcc允许作为一个扩展)转换为指向一个指针int,然后操纵指向对象,就像它是一个int.指针指向int通常不能指向类型的对象,long long因此允许gcc假定写入int(通过指针)的操作不会影响具有类型的对象long long.

因此,n在它最初分配的时间和随后打印的时间之间缓存值是合法的.没有有效的写操作可能会改变其值.

要阅读的特定开关和文档是-fstrict-aliasing.


Eri*_*rik 6

你正在打破严格的别名.用-Wall编译会给你一个dereferencing type-punned pointer警告.参见例如http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html