8

如果没有 -O2,此代码将打印84 84,带有 O2 标志的输出为84 42gcc 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;
}
4

3 回答 3

19

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

您的代码具有未定义的行为,因为您将指向 a 的指针long long(gcc 允许作为扩展)转换为指向 an 的指针int,然后将指向的对象当作int. 指向-的指针int通常不能指向类型的对象long long因此允许 gcc 假设写入int(通过指针)的操作不会影响具有 type 的对象long long

因此,缓存n最初分配的时间和随后打印的时间之间的值是合法的。不有效的写操作可以改变它的值。

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

于 2011-03-04T15:37:04.640 回答
6

你打破了严格的混叠。使用 -Wall 编译应该会给你一个dereferencing type-punned pointer警告。参见例如http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

于 2011-03-04T15:38:36.817 回答
1

我在 Linux/i386 上使用 GCC 4.4.4 得到了相同的结果。

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

于 2011-03-04T15:39:24.110 回答