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?
What you missed is that bit shift operations on ints are mod 32. Since
0x1111is anint, the operation is0x1111 << (32 % 32), which is0x1111 << 0, which is just0x1111.What you probably want is
0x1111L << 32.From section 7.9 of the C# spec:
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
& 0x1Fon 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.