Note that there are some explanatory texts on larger screens.

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

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload