user4255: I'm using a supplied library which uses a number of (non-sequential) outputs to latch a multiplexer. The code looks (in part) like this:
 digitalWrite(_S0, (chan & 1));    
 digitalWrite(_S1, (chan & 3)>>1); 
 digitalWrite(_S2, (chan & 7)>>2); 
 digitalWrite(_S3, (chan & 15)>>3); 

Those masks seem a little odd, but it would work. More natural to me would be:
 digitalWrite(_S0, (chan & 1));    
 digitalWrite(_S1, (chan & 2)>>1); 
 digitalWrite(_S2, (chan & 4)>>2); 
 digitalWrite(_S3, (chan & 8)>>3); 

But overall, would it be more efficient to do this?
 digitalWrite(_S0,       (chan & 1));    
 digitalWrite(_S1, (bool)(chan & 2)); 
 digitalWrite(_S2, (bool)(chan & 4)); 
 digitalWrite(_S3, (bool)(chan & 8)); 

...or is shifting already pretty efficient?
I've actually re-written the code to build a mask and use PORTx to latch it all at once, so this is really an academic question, but I'm still curious.

user13425: If you look at the assembly code the compiler produces, you can see it compiles to the exact same thing - when using a constant.:
void setup() {
  ....
  digitalWrite(_S1, (chan & 2)>>1); 
 282:   84 e0           ldi r24, 0x04   ; 4
 284:   0e 94 6b 00     call    0xd6    ; 0xd6 <digitalWrite.constprop.0>
 ....
  digitalWrite(_S1, (bool)(chan & 2)); 
 29a:   84 e0           ldi r24, 0x04   ; 4
 29c:   0e 94 6b 00     call    0xd6    ; 0xd6 <digitalWrite.constprop.0>

However, using a variable produces different results:
void loop() {
  digitalWrite(_S0, (chan & 1));    
 2a2:   c0 91 00 01     lds r28, 0x0100 ; 0x800100 <__data_start>
 2a6:   d0 91 01 01     lds r29, 0x0101 ; 0x800101 <__data_start+0x1>
 2aa:   6c 2f           mov r22, r28
 2ac:   61 70           andi    r22, 0x01   ; 1
 2ae:   83 e0           ldi r24, 0x03   ; 3
 2b0:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>
  digitalWrite(_S1, (chan & 2)>>1); 
 2b4:   6c 2f           mov r22, r28
 2b6:   66 95           lsr r22
 2b8:   61 70           andi    r22, 0x01   ; 1
 2ba:   84 e0           ldi r24, 0x04   ; 4
 2bc:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>
  digitalWrite(_S2, (chan & 4)>>2); 
 2c0:   c2 fb           bst r28, 2
 2c2:   66 27           eor r22, r22
 2c4:   60 f9           bld r22, 0
 2c6:   85 e0           ldi r24, 0x05   ; 5
 2c8:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>
  digitalWrite(_S3, (chan & 8)>>3); 
 2cc:   c3 fb           bst r28, 3
 2ce:   66 27           eor r22, r22
 2d0:   60 f9           bld r22, 0
 2d2:   86 e0           ldi r24, 0x06   ; 6
 2d4:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>

 ....

  digitalWrite(_S0,       (chan & 1));    
 2a2:   c0 91 00 01     lds r28, 0x0100 ; 0x800100 <__data_start>
 2a6:   d0 91 01 01     lds r29, 0x0101 ; 0x800101 <__data_start+0x1>
 2aa:   6c 2f           mov r22, r28
 2ac:   61 70           andi    r22, 0x01   ; 1
 2ae:   83 e0           ldi r24, 0x03   ; 3
 2b0:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>
  digitalWrite(_S1, (bool)(chan & 2)); 
 2b4:   be 01           movw    r22, r28
 2b6:   76 95           lsr r23
 2b8:   67 95           ror r22
 2ba:   61 70           andi    r22, 0x01   ; 1
 2bc:   84 e0           ldi r24, 0x04   ; 4
 2be:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>
  digitalWrite(_S2, (bool)(chan & 4)); 
 2c2:   be 01           movw    r22, r28
 2c4:   76 95           lsr r23
 2c6:   67 95           ror r22
 2c8:   76 95           lsr r23
 2ca:   67 95           ror r22
 2cc:   61 70           andi    r22, 0x01   ; 1
 2ce:   85 e0           ldi r24, 0x05   ; 5
 2d0:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>
  digitalWrite(_S3, (bool)(chan & 8)); 
 2d4:   be 01           movw    r22, r28
 2d6:   23 e0           ldi r18, 0x03   ; 3
 2d8:   76 95           lsr r23
 2da:   67 95           ror r22
 2dc:   2a 95           dec r18
 2de:   e1 f7           brne    .-8         ; 0x2d8 <main+0xc0>
 2e0:   61 70           andi    r22, 0x01   ; 1
 2e2:   86 e0           ldi r24, 0x06   ; 6
 2e4:   0e 94 76 00     call    0xec    ; 0xec <digitalWrite>


user7508: I tried compiling your three snippets with avr-gcc 4.9.2 at the -Os
optimization level (standard with Arduino) but without -flto. The
results were:

The first snippet generated inefficient code: the ands and shifts were
translated in assembly quite literally, the shifts were done on
16 bits even though chan was declared uint8_t, and the last
shift was even implemented as a loop roughly equivalent to
uint16_t tmp1 = chan & 15; uint8_t tmp2 = 3; while (--tmp2) tmp1 <<= 1;
The second and third snippets were translated identically and
efficiently, using the bst (bit store) and bld (bit load)
instructions to copy the relevant bit of chan into the second
argument of the digitalWrite() call.

Personally I would just write
digitalWrite(_S0, chan & 1);    
digitalWrite(_S1, chan & 2); 
digitalWrite(_S2, chan & 4); 
digitalWrite(_S3, chan & 8);

as digitalWrite() expects an integer as its second argument, and it
interprets it just like the (bool) cast does. If you want to be sure
to always call digitalWrite() with either 0 (LOW) or 1 (HIGH),
then use either your second of third form. The first form seems formally
equivalent to the second, but since it is not an usual C idiom, the
compiler could not catch the optimization opportunity.

4255: <p>I'm using a supplied library which uses a number of (non-sequential) outputs to latch a multiplexer. The code looks (in part) like this:</p>

<pre><code> digitalWrite(_S0, (chan &amp; 1));    
 digitalWrite(_S1, (chan &amp; 3)&gt;&gt;1); 
 digitalWrite(_S2, (chan &amp; 7)&gt;&gt;2); 
 digitalWrite(_S3, (chan &amp; 15)&gt;&gt;3); 
</code></pre>

<p>Those masks seem a little odd, but it would work. More natural to me would be:</p>

<pre><code> digitalWrite(_S0, (chan &amp; 1));    
 digitalWrite(_S1, (chan &amp; 2)&gt;&gt;1); 
 digitalWrite(_S2, (chan &amp; 4)&gt;&gt;2); 
 digitalWrite(_S3, (chan &amp; 8)&gt;&gt;3); 
</code></pre>

<p>But overall, would it be more efficient to do this?</p>

<pre><code> digitalWrite(_S0,       (chan &amp; 1));    
 digitalWrite(_S1, (bool)(chan &amp; 2)); 
 digitalWrite(_S2, (bool)(chan &amp; 4)); 
 digitalWrite(_S3, (bool)(chan &amp; 8)); 
</code></pre>

<p>...or is shifting already pretty efficient?</p>

<p>I've actually re-written the code to build a mask and use PORTx to latch it all at once, so this is really an academic question, but I'm still curious.</p>
 13425: <p>If you look at the assembly code the compiler produces, you can see it compiles to the exact same thing - when using a constant.:</p>

<pre><code>void setup() {
  ....
  digitalWrite(_S1, (chan &amp; 2)&gt;&gt;1); 
 282:   84 e0           ldi r24, 0x04   ; 4
 284:   0e 94 6b 00     call    0xd6    ; 0xd6 &lt;digitalWrite.constprop.0&gt;
 ....
  digitalWrite(_S1, (bool)(chan &amp; 2)); 
 29a:   84 e0           ldi r24, 0x04   ; 4
 29c:   0e 94 6b 00     call    0xd6    ; 0xd6 &lt;digitalWrite.constprop.0&gt;
</code></pre>

<p>However, using a variable produces different results:</p>

<pre><code>void loop() {
  digitalWrite(_S0, (chan &amp; 1));    
 2a2:   c0 91 00 01     lds r28, 0x0100 ; 0x800100 &lt;__data_start&gt;
 2a6:   d0 91 01 01     lds r29, 0x0101 ; 0x800101 &lt;__data_start+0x1&gt;
 2aa:   6c 2f           mov r22, r28
 2ac:   61 70           andi    r22, 0x01   ; 1
 2ae:   83 e0           ldi r24, 0x03   ; 3
 2b0:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
  digitalWrite(_S1, (chan &amp; 2)&gt;&gt;1); 
 2b4:   6c 2f           mov r22, r28
 2b6:   66 95           lsr r22
 2b8:   61 70           andi    r22, 0x01   ; 1
 2ba:   84 e0           ldi r24, 0x04   ; 4
 2bc:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
  digitalWrite(_S2, (chan &amp; 4)&gt;&gt;2); 
 2c0:   c2 fb           bst r28, 2
 2c2:   66 27           eor r22, r22
 2c4:   60 f9           bld r22, 0
 2c6:   85 e0           ldi r24, 0x05   ; 5
 2c8:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
  digitalWrite(_S3, (chan &amp; 8)&gt;&gt;3); 
 2cc:   c3 fb           bst r28, 3
 2ce:   66 27           eor r22, r22
 2d0:   60 f9           bld r22, 0
 2d2:   86 e0           ldi r24, 0x06   ; 6
 2d4:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;

 ....

  digitalWrite(_S0,       (chan &amp; 1));    
 2a2:   c0 91 00 01     lds r28, 0x0100 ; 0x800100 &lt;__data_start&gt;
 2a6:   d0 91 01 01     lds r29, 0x0101 ; 0x800101 &lt;__data_start+0x1&gt;
 2aa:   6c 2f           mov r22, r28
 2ac:   61 70           andi    r22, 0x01   ; 1
 2ae:   83 e0           ldi r24, 0x03   ; 3
 2b0:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
  digitalWrite(_S1, (bool)(chan &amp; 2)); 
 2b4:   be 01           movw    r22, r28
 2b6:   76 95           lsr r23
 2b8:   67 95           ror r22
 2ba:   61 70           andi    r22, 0x01   ; 1
 2bc:   84 e0           ldi r24, 0x04   ; 4
 2be:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
  digitalWrite(_S2, (bool)(chan &amp; 4)); 
 2c2:   be 01           movw    r22, r28
 2c4:   76 95           lsr r23
 2c6:   67 95           ror r22
 2c8:   76 95           lsr r23
 2ca:   67 95           ror r22
 2cc:   61 70           andi    r22, 0x01   ; 1
 2ce:   85 e0           ldi r24, 0x05   ; 5
 2d0:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
  digitalWrite(_S3, (bool)(chan &amp; 8)); 
 2d4:   be 01           movw    r22, r28
 2d6:   23 e0           ldi r18, 0x03   ; 3
 2d8:   76 95           lsr r23
 2da:   67 95           ror r22
 2dc:   2a 95           dec r18
 2de:   e1 f7           brne    .-8         ; 0x2d8 &lt;main+0xc0&gt;
 2e0:   61 70           andi    r22, 0x01   ; 1
 2e2:   86 e0           ldi r24, 0x06   ; 6
 2e4:   0e 94 76 00     call    0xec    ; 0xec &lt;digitalWrite&gt;
</code></pre>
 7508: <p>I tried compiling your three snippets with avr-gcc 4.9.2 at the <code>-Os</code>
optimization level (standard with Arduino) but <em>without</em> <code>-flto</code>. The
results were:</p>

<ul>
<li><p>The first snippet generated inefficient code: the ands and shifts were
translated in assembly quite literally, the shifts were done on
16&nbsp;bits even though <code>chan</code> was declared <code>uint8_t</code>, and the last
shift was even implemented as a loop roughly equivalent to
<code>uint16_t tmp1 = chan &amp; 15; uint8_t tmp2 = 3; while (--tmp2) tmp1 &lt;&lt;= 1;</code></p></li>
<li><p>The second and third snippets were translated identically and
efficiently, using the <code>bst</code> (bit store) and <code>bld</code> (bit load)
instructions to copy the relevant bit of <code>chan</code> into the second
argument of the <code>digitalWrite()</code> call.</p></li>
</ul>

<p>Personally I would just write</p>

<pre><code>digitalWrite(_S0, chan &amp; 1);    
digitalWrite(_S1, chan &amp; 2); 
digitalWrite(_S2, chan &amp; 4); 
digitalWrite(_S3, chan &amp; 8);
</code></pre>

<p>as <code>digitalWrite()</code> expects an integer as its second argument, and it
interprets it just like the <code>(bool)</code> cast does. If you want to be sure
to always call <code>digitalWrite()</code> with either 0 (<code>LOW</code>) or 1 (<code>HIGH</code>),
then use either your second of third form. The first form seems formally
equivalent to the second, but since it is <em>not</em> an usual C idiom, the
compiler could not catch the optimization opportunity.</p>
