Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
}
like image 294
Leonid Avatar asked Mar 04 '11 15:03

Leonid


People also ask

How many types of shift operators are there?

Shift operators are classified into two types based on the shifting position of the bits.

What is the difference between Left Shift and Right shift operator?

The bitwise shift operators move the bit values of a binary object. The left operand specifies the value to be shifted. The right operand specifies the number of positions that the bits in the value are to be shifted.

What are the two basic shift operations?

The two basic types are the arithmetic left shift and the arithmetic right shift.


3 Answers

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.

like image 102
CB Bailey Avatar answered Oct 04 '22 07:10

CB Bailey


You're breaking strict aliasing. Compiling with -Wall should give you a dereferencing type-punned pointer warning. See e.g. http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

like image 21
Erik Avatar answered Oct 04 '22 08:10

Erik


I get the same results with GCC 4.4.4 on Linux/i386.

The program's behavior is undefined, since it violates the strict aliasing rule.

like image 43
Fred Foo Avatar answered Oct 04 '22 08:10

Fred Foo