I know Arduino language isn't strictly C/C++, but many of us just use and expect a lot of C behavior to work in sketches.
I was just debugging a weird time related bug and came across an unobvious casting / promotion issue. I'm sure others must have hit it but I'd appreciate some feedback as it feels like a compiler promotion bug to me. Certainly for me, it's been responsible for several bugs in sketches where I've tended to use expressions like 'valueMs = (numSeconds * 1000)', especially when numSeconds > 32.
I am using IDE 1.5.4.
So, if you do this:
unsigned long a = 0;
a = a + 33000;
You get 33000.
No surprises.
Now do this (quite common if a is a time in millisecond):
a = a + (33 * 1000);
You will get 4294934760.
The brackets don't matter.
If you repeat the above with 32000 instead, it will be fine.
So it seems rvalues are not promoted to the largest type's resolution if you use an expression like that. It looks like it is using 16bit signed short for the RHS. Isn't this wrong? At least in C/C++ world, where rvalues should get promoted to the largest size of the various operands, and since 'a' is a unsigned long and on the RHS, I would expect (33*1000) to get promoted to unsigned long.
You can work round it in various way,
e.g.
a = a + ((unsigned long)33*1000);
a = a + (33.0 * 1000);
etc.
i.e. force explicit upcasts but this is not obvious.
This triggered 'weird' bugs in code if you use expressions like this:
if ((unsigned long)(millis() - waitUntil) >= (60 * 1000) {
Example to repro the problem:
unsigned long a = 0;
unsigned long b = 0;
void loop() {
Serial.print ("a = ");
Serial.println (a,DEC);
Serial.print ("b = ");
Serial.println (b,DEC);
a = a + 33000;
b = b + (33*1000); // not ok
delay (250);
}
My ouput (a and b should be the same but they are not):
a = 0
b = 0
a = 33000
b = 4294934760
a = 66000
b = 4294902224
a = 99000
b = 4294869688
a = 132000
b = 4294837152
Chris