8

-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;
}
4

3 に答える 3

19

gccで最適化を使用する場合、式のタイプに基づいて特定の仮定を使用して、不要な読み取りの繰り返しを回避し、変数をメモリに保持できるようにすることができます。

long long(gccが拡張として許可する)へのポインターをへのポインターにキャストしint、それがであるかのようにオブジェクトへのポインターを操作するため、コードの動作は未定義ですint。ポインタintは通常、型のオブジェクトを指すことができないため、gccは、 (ポインタを介して)に書き込む操作が型のオブジェクトに影響を与えないlong longと想定することができます。intlong 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上のGCC4.4.4でも同じ結果が得られます。

プログラムの動作は、厳密なエイリアシング規則に違反しているため、未定義です。

于 2011-03-04T15:39:24.110 に答える