Search code examples
c++gcc64-bitcompiler-optimizationstrict-aliasing

Different behavior of shift operator with -O2 and without


Without -O2 this code prints 84 84, with O2 flag the output is 84 42. The code was compiled using gcc 4.4.3. on 64-bit Linux platform. Why the output for the following code is different?

Note that when compiled with -Os the output is 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;
}

Solution

  • When you use optimization with gcc, it can use certain assumptions based on the type of expressions to avoid repeating unnecessary reads and to allow retaining variables in memory.

    Your code has undefined behaviour because you cast a pointer to a long long (which gcc allows as an extenstion) to a pointer to an int and then manipulate the pointed-to-object as if it were an int. A pointer-to-int cannot normally point to an object of type long long so gcc is allowed to assume that an operation that writes to an int (via a pointer) won't affect an object that has type long long.

    It is therefore legitimate of it to cache the value of n between the time it was originally assigned and the time at which it is subsequently printed. No valid write operation could have changed its value.

    The particular switch and documentation to read is -fstrict-aliasing.