4

Consider the following code:

#include <hal_types.h>

int main() {

    uint16 crc16;         // hal_types.h: typedef unsigned short  uint16;

    crc16 = 0x43;         // debugger: crc16 == 0x0043, as expected
    crc16 = crc16 << 8;   // crc16 == 0x0000 ????

    return 0;
}

This code is running on a TI CC1111 SoC (with an 8051 core), and compiled/debugged using IAR EW8051 8.10.3, configured to use the C99 dialect, with no optimization. The values in the comments were observed with the IAR debugger (same results using either simulator or actual device).

I would expect that after crc16 = crc16 << 8;, crc16 would have the value 0x4300, not 0x0000.

According to the C99 standard (well, the May 2005-05-06 draft), section 6.5.7.3-4.

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

My take on this is that the result type should be an unsigned 16-bit integer, with the value ((0x0043)*(2^8)) % 0x10000 == 0x4300.

Am I missing something? Thanks.

David
  • 1,167
  • 15
  • 24
  • Why are you using 0xB4 when your code says 0x43? – unwind Apr 10 '12 at 14:36
  • I assume that you tried `crc16 <<= 8;`, right? It should make no difference, though. – Sergey Kalinichenko Apr 10 '12 at 14:39
  • Sorry about the discrepancy (fixed). I edited this from a more detailed version of the question I posted on TI's forum (http://e2e.ti.com/support/low_power_rf/f/156/t/181338.aspx) – David Apr 10 '12 at 14:42
  • @dasblinkenlight: Same results with `crc16 <<= 8;` – David Apr 10 '12 at 14:44
  • 3
    @David Could you post a dissembled version of the code the compiler generated? I would expect to see a move of the lower eight bits into the higher eight bits (or perhaps a swap) followed by clearing the lower eight bits. – Sergey Kalinichenko Apr 10 '12 at 14:48
  • @dasblinkenlight: I could see in the assembler output that it was just setting crc16 to zero. For whatever reason, that made me try using the value, and now I get the right value (see above). Thanks. – David Apr 10 '12 at 15:05
  • maybe that's just the optimizer doing its part. Since you don't use the result of the assignment so it's being optimized out – phuclv Oct 16 '13 at 06:33

2 Answers2

1

I figured out what's going on. Even though there's no optimization, the fact that I didn't use crc16 seems to have changed the semantics. If I add the following lines at the end,

if (crc16) 
        crc16 = 0x1234;

then crc16 has the expected value (0x4300) after crc16 = crc16 << 8;.

David
  • 1,167
  • 15
  • 24
1

You could also declare crc16 as volatile, as Adam Casey commented.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Jamie
  • 11
  • 1
  • Ordinarily we delete "That worked great!" answers, but in this case, the original quote was a comment and really needs to be posted in an answer for voting purposes. – Michael Myers Oct 07 '13 at 17:49