Hello all!
I have stumbled upon a code construct that the Arduino compiler mis-compiles.
Loops that use an unsigned integer as the counter variable do not compile correctly if the loop's exit condition is "<=65535U" or "<=0xFFFFU". The object code / assembly language that is produced is wrong - it never checks for the ending condition of the loop, so the loop ends up being an infinite loop. Here are two examples of loops that cause this bug to manifest...
unsigned int ui = 16384U;
do { whatever } while (ui <= 65535U);
unsigned int ui;
for (ui = 0x6000U; ui <= 0xFFFFU; ui++) { whatever }
The object code for the 'for' loop above that is produced by the Arduino software is as follows...
126: e0 e0 ldi r30, 0x00 ; 0
128: f0 e6 ldi r31, 0x60 ; 96
12c: whatever
12e: fe cf rjmp .-4 ; 0x12c <setup+0x6>
Note that the counter variable (in registers 30 & 31) is never compared to anything, and there is no conditional branch that operates on the result of the comparison. Instead, there is a unconditional jump back to the top of the loop, causing it to run forever.
The attached sketch demonstrates this. The "Serial.println()" before the loop gets invoked, but the "Serial.println()" after the loop never does. A quick look at the assembly code produced by the compiler shows why - the loop never terminates, and the counter variable "ui" keeps incrementing and then wrapping forever.
I have tested this on a Mega 2560 and on a Duemilanove 328, using the 1.0.1 version and the 1.0.3 version of the Arduino software, on two different computers.
Note that if you change the loop's ending condition to "<=65534", or "<65535", or "<= 60000", etc, then the compiler produces the correct object code and the program runs as expected. There is something special about taking the counter variable all the way up to the biggest number that fits in a 16-bit unsigned int (65535).
This situation seems so odd to me that I thought I would post it and see if I could get some independent confirmation before I submitted a bug report.
Thanks!
kc-science
CompilerBug.ino (278 Bytes)