rpg
rpg

Reputation: 975

Bit shift compiler bug or a corner case?

The following code outputs 0,1,32,33. Which is counter intuitive to say the least. But if I replace the literal 1 with the type annonated constant "ONE", the loop runs fine.

This is with gcc 4.6.2 and -std=c++0x.

#include<iostream>
#include<cstdint>
using namespace std;
int main()
    {
    int64_t bitmask = 3;
    int64_t k;
    const int64_t ONE = 1;
    cout<<"bitmask = "<<bitmask<<endl;

    for(k=0; k<64; k++)
        {
        if(bitmask & (1<<k))
            {
            cout<<"k="<<k<<endl;
            }
        }

    return 0;
    } 

EDIT Question: As Ben pointed out, 1 is seen to be 32 bit wide by default. Why is it not promoted to 64 bits when it's co-operand is 64 bits.

SOLUTION

No. << does not require that each side have the same type. After all, why make the right side an int64_t when the maximum shift available fits in a char? The promotion only occurs when you are dealing with arithmetic operators, not all operators.

Copied from Bill's comments below

Upvotes: 5

Views: 954

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283793

This is a problem: (1<<k).

1 is a integral literal that fits in an int.

If int has fewer than 64 bits on your platform, then (1<<k) will have undefined behavior toward the end of the loop, when k is large. In your case, the compiler is using an Intel bitshift instruction, and the undefined behavior comes out the way Intel defines shifts larger than the operand size -- the high bits are ignored.

You probably want (1LL<<k)


What the standard says (section 5.8 expr.shift):

The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

This in contrast to the wording "The usual arithmetic conversions are performed for operands of arithmetic or enumeration type." which is present for e.g. addition and subtraction operators.

This language didn't change between C++03 and C++11.

Upvotes: 8

Related Questions