tags:

views:

824

answers:

7

Why this code does not write 0 as a last element but 18446744073709551615? (compiled with g++)

#include <iostream>

using namespace std;
int main(){
    unsigned long long x = (unsigned long long) (-1);
    for(int i=0; i <= 64; i++)
     cout << i << " " << (x >> i) << endl;
    cout << (x >> 64) << endl;
    return 0;
}
+1  A: 

well, you are shifting one too many times. you are shifting from 0 to 64 inclusive which is a total of 65 times. You generally want:

for(int i=0; i < 64; i++)
    ....
Evan Teran
+5  A: 

Shifting a number a number of bits that is equal to or larger than its width is undefined behavior. You can only safely shift a 64-bit integer between 0 and 63 positions.

Tyler McHenry
this is wrong, the max amount of a right shift is 31, i.e. the shift amount is always masked by 0x1F internally. See intel manuals on SHR instruction.
jn_
@jn: Intel manuals define it for "x86 assembly." It's undefined at C level.
Mehrdad Afshari
@Mehrdad: correct - i just checked the assembly output of MSVC compiled code. If the shift amount is greater than 32 the amount is masked with 0x1F, if the amount is greater than 64, the result of the shift is zero.
jn_
+8  A: 

When you shift a value by more bits than word size, it usually gets shifted by mod word-size. Basically, shifting it by 64 means shifting by 0 bits which is equal to no shifting at all. You shouldn't rely on this though as it's not defined by the standard and it can be different on different architectures.

Mehrdad Afshari
+2  A: 

This warning from the compiler should be a hint:

"warning: right shift count >= width of type"

This results in undefined behavior:

http://sourcefrog.net/weblog/software/languages/C/bitshift.html

nsanders
+1  A: 

I get:

test.c:8: warning: right shift count >= width of type

so perhaps it's undefined behavior?

Peter K.
+1  A: 

You overflow the shift. If you've noticed, GCC even warns you:

warning: right shift count >= width of type

How come? You include 64 as a valid shift, which is an undefined behavior. counting from 0 to 64 there are 65 numbers (0 included). 0 being the first bit (much like arrays).

#include <iostream>

using namespace std;
int main(){
    unsigned long long x = (unsigned long long) (-1);
    for(int i=0; i < 64; i++)
        cout << i << " " << (x >> i) << endl;
    cout << (x >> 63) << endl;
    return 0;
}

Will produce the output you'd expect.

LiraNuna
A: 

The bit pattern of -1 looks like 0xFFFFFFFFFFFFFFFF in hex, for 64 bit types. Thus if you print it as an unsigned variable you will see the largest value an unsigned 64 bit variable can hold, i.e. 18446744073709551615.

When bit shifting we don't care what a value means in this case, i.e. it doesn't matter if the variable is signed or unsigned it is treated the same way (shifting all bits one step to the right in this case).

It does matter if the value is signed or not when you're right-shifting. Signed right shift fills the highest bits to the sign bit, unsigned right shift will fill them with 0. Effectively, right shift by "k" bits will have the same effect of dividing by 2^k.
Mehrdad Afshari