13
volatile uint16_t r;
unsigned char poly = 0x07;
unsigned char c = 0;

r = (c << 8) ^ poly;

When the code is compiled with gcc on Linux, r is 7.
When the same code is compiled by Microchip C18, r is 0.
Why?

If I change it to:

volatile uint16_t r;
uint16_t poly = 0x07;
uint16_t c = 0;

r = (c << 8) ^ poly;

r becomes 7 in C18, too.

There is a section about integer promotion in the C18 manual, but I don't think it has something to do with my question. Anyway, here it is:

ISO mandates that all arithmetic be performed at int precision or greater. By default, MPLAB C18 will perform arithmetic at the size of the largest operand, even if both operands are smaller than an int. The ISO mandated behavior can be instated via the -Oi command-line option.

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
AndreKR
  • 32,613
  • 18
  • 106
  • 168

2 Answers2

3

Since c << 8 is undefined in this compiler, the result of xor can't be predicted. The result could be anything the compiler chooses.

See What Every C Programmer Should Know About Undefined Behavior for an introduction to undefined behavior, especially the section "Oversized Shift Amounts".

ergosys
  • 47,835
  • 5
  • 49
  • 70
2

c << 8 with c a char is basically sending all the bits to oblivion. As specified in the doc, both c and 8 fit in a char, so everything is done using char.

c << 8UL may change the deal.

Joel Falcou
  • 6,247
  • 1
  • 17
  • 34
  • This explains what happens to `c` if any of the bits were set, but doesn't explain why the `^ poly` fragment disappears too. – viraptor May 23 '11 at 00:54
  • 1
    Actually, the standard also says that shifting an integer of size `n` bits by `n` is undefined behavior, so who knows what shifting a char by 8 does on this compiler? (note: on a standard compiler, `c<<8` is defined by virtue of the promotion to `int` that this compiler removes) – Pascal Cuoq May 23 '11 at 01:21
  • Oh, interesting. That explains why the results I am getting are, well, undefined. I even managed to get 0x62 instead of 0x00 and in another variant I got a disassembly that completely ignored that line. That's the answer I guess. – AndreKR May 23 '11 at 02:14