title: c standard and bitshifts
body: <p>This question was first inspired by the (unexpected) results of this code:</p>
  
  <pre><code>uint16_t   t16 = 0;
  uint8_t     t8 = 0x80;
  uint8_t t8_res;
  
  t16    = (t8 &lt;&lt; 1);
  t8_res = (t8 &lt;&lt; 1);
  
  printf("t16: %x\n", t16);    // Expect 0, get 0x100
  printf(" t8: %x\n", t8_res); // Expect 0, get 0
  </code></pre>
  
  <p>But it turns out this makes sense:</p>
  
  <p><strong>6.5.7 Bitwise shift operators</strong></p>
  
  <p><em>Constraints</em></p>
  
  <p><em><strong>2</strong> Each of the operands shall have integer type</em></p>
  
  <p>Thus the originally confused line is equivalent to:</p>
  
  <pre><code>t16 = (uint16_t) (((int) t8) &lt;&lt; 1);
  </code></pre>
  
  <p>A little non-intuitive IMHO, but at least well-defined.</p>
  
  <p>Ok, great, but then we do:</p>
  
  <pre><code>{
  uint64_t t64 = 1;
  t64 &lt;&lt;= 31;
  printf("t64: %lx\n", t64); // Expect 0x80000000, get 0x80000000
  t64 &lt;&lt;= 31;
  printf("t64: %lx\n", t64); // Expect 0x0, get 0x4000000000000000
  }
  </code></pre>
  
  <p>// edit: following the same literal argument as above, the following should be equivalent:</p>
  
  <pre><code>t64 = (uint64_t) (((int) t64) &lt;&lt; 31);
  </code></pre>
  
  <p>// hence my confusion / expectation [end_edit]</p>
  
  <p>Now, we get the intuitive result, but not what would be derived from my (literal) reading of the standard.  When / how does this "further automatic type promotion" take place? Or is there a limitation elsewhere that a type can never be demoted (that would make sense?), in that case, how do the promotion rules apply for:</p>
  
  <pre><code>uint32_t &lt;&lt; uint64_t
  </code></pre>
  
  <p>Since the standard does say both arguments are promoted to int; should both arguments be promoted to the same type here?</p>
  
  <p>// edit:</p>
  
  <p>More specifically, what should the result of:</p>
  
  <pre><code>uint32_t t32 = 1;
  uint64_t t64_one = 1;
  uint64_t t64_res;
  
  t64_res = t32 &lt;&lt; t64_one;
  </code></pre>
  
  <p>// end edit</p>
  
  <p>The answer to the above question is resolved when we recognize that the spec does not demand a promotion to <code>int</code> specifically, rather to an <code>integer type</code>, which uint64_t qualifies as.</p>
  
  <p>// CLARIFICATION EDIT:</p>
  
  <p>Ok, but now I am confused again.  Specifically, if <code>uint8_t</code> is an integer type, then why is it being promoted to <code>int</code> at all? It does not seem to be related to the constant int 1, as the following exercise demonstrates:</p>
  
  <pre><code>{
  uint16_t t16 = 0;
  uint8_t t8 = 0x80;
  uint8_t t8_one = 1;
  uint8_t t8_res;
  
  t16 = (t8 &lt;&lt; t8_one);
  t8_res = (t8 &lt;&lt; t8_one);
  
  printf("t16: %x\n", t16);
  printf(" t8: %x\n", t8_res);
  }
  
  t16: 100
   t8: 0
  </code></pre>
  
  <p>Why is the (t8 &lt;&lt; t8_one) expression being promoted if uint8_t is an integer type?</p>
  
  <p>--</p>
  
  <p>For reference, I'm working from ISO/IEC 9899:TC9, WG14/N1124 May 6, 2005.  If that's out of date and someone could also provide a link to a more recent copy, that'd be appreciated as well.</p>