I think I'm going insane with this.
I have a a piece of code that needs to create an (unsigned) integer with N
consequent bits set to 1. To be exact I have a bitmask, and in some situations I'd like to set it to a solid rnage.
I have the following function:
void MaskAddRange(UINT& mask, UINT first, UINT count)
{
mask |= ((1 << count) - 1) << first;
}
In simple words: 1 << count
in binary representation is 100...000
(number of zeroes is count
), subtracting 1 from such a number gives 011...111
, and then we just left-shift it by first
.
The above should yield correct result, when the following obvious limitation is met:
first + count <= sizeof(UINT)*8 = 32
Note that it should also work correctly for "extreme" cases.
- if
count = 0
we have(1 << count) = 1
, and hence((1 << count) - 1) = 0
. - if
count = 32
we have(1 << count) = 0
, since the leading bit overflows, and according to C/C++ rules bitwise shift operators are not cyclic. Then((1 << count) - 1) = -1
(all bits set).
However, as turned out, for count = 32
the formula doesn't work as expected. As discovered:
UINT n = 32;
UINT x = 1 << n;
// the value of x is 1
Moreover, I'm using MSVC2005 IDE. When I evaluate the above expression in the debugger, the result is 0. However when I step over the above line, x
gets value of 1. Lokking via the disassembler we see the following:
mov eax,1
mov ecx,dword ptr [ebp-0Ch] // ecx = n
shl eax,cl // eax <<= LOBYTE(ecx)
mov dword ptr [ebp-18h],eax // n = ecx
There's no magic indeed, compiler just used shl
instruction. Then it seems that shl
doesn't do what I expected it should do. Either CPU decides to ignore this instruction, or the shift is treated modulo 32, or donno what.
My questions are:
- What is the correct behavior of
shl
/shr
instructions? - Is there a CPU flag controlling the bitshift instructions?
- Is this according to C/C++ standard?
Thanks in advance
Edit:
Thanks for answers. I've realized that (1) shl
/shr
indeed treat operand modulo 32 (or & 0x1F) and (2) C/C++ standard treats shift by more than 31 bits as undefined behavior.
Then I have one more question. How can I rewrite my "masking" expression to cover this extreme case too. It should be without branching (if
, ?
). What'd be the simplest expression?