sebf
sebf

Reputation: 2972

What is the cause of the odd behaviour of the bitwise operator in the following code?

I have a method in my C# application which is attempting to pack an integer, but the shift operator is behaving strangely.
The comments in the code below show the contents of code as seen by the debugger after the execution of the line.

        long code = 0;          //0x0000000000000000
        code += (0x1111 << 32); //0x0000000000001111
        code += (0x2222 << 16); //0x0000000022221111
        code += (0x3333);       //0x0000000022224444

Take the first line, I would expect that the code contained in parentheses would be executed first, which would result in 0x1111 being shifted left by 32 bits, yet it isn't, but on the next line the shift does take place, and in the correct place as well (i.e. 0x2222 must be shifted before the add otherwise the result would be 0x33330000).

What have I missed about the operator that explains this?

Upvotes: 2

Views: 159

Answers (2)

Gabe
Gabe

Reputation: 86848

What you missed is that bit shift operations on ints are mod 32. Since 0x1111 is an int, the operation is 0x1111 << (32 % 32), which is 0x1111 << 0, which is just 0x1111.

What you probably want is 0x1111L << 32.

From section 7.9 of the C# spec:

  • When the type of x is int or uint, the shift count is given by the low-order five bits of count. In other words, the shift count is computed from count & 0x1F.

  • When the type of x is long or ulong, the shift count is given by the low-order six bits of count. In other words, the shift count is computed from count & 0x3F.

On some hardware architectures, shifting an int by 32 will yield 0, while other architectures will yield the same int. In order to have consistent behavior, the designers of C# had to choose one of those options. The current behavior simply requires performing & 0x1F on the shift count on architectures that otherwise yield 0. However, always returning 0 would require a comparison and a branch on architectures that yield the int. Since branches tend to be expensive, it makes sense that they chose the option that is fastest in the most cases.

Upvotes: 6

Daniel A. White
Daniel A. White

Reputation: 191058

I believe its because 0x1111 is treated as an int.

Upvotes: 1

Related Questions