Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 596
rpg Avatar asked Nov 24 '11 06:11

rpg


1 Answers

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.

like image 168
Ben Voigt Avatar answered Sep 29 '22 07:09

Ben Voigt