comparison of two unsigned bytes strange behavior

Hi all,

The millis overflow issue is quite common on the web and on this forum.
I understand that whenever you subtract an older time from a newer one, you get the correct unsigned result.

I just wanted to see it in action.
So i made this simple sketch, and it does not seem to behave correctly:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  unsigned char start = 253;
  unsigned char mil = 253;
  unsigned char period = 3;
  mil++; // 254
  mil++; // 255
  mil++; // 0
  mil++; // 1
  mil++; // 2
  Serial.println((unsigned char)mil, DEC); // prints 2
  Serial.println(mil, DEC); // prints 2
  Serial.println();
  Serial.println((unsigned char)(mil - start), DEC); // prints 5
  Serial.println(mil - start, DEC); // prints -251
  if(mil - start >= period){ // DOES NOT ENTER IF
      Serial.println("Time passed"); // NOT PRINTED
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Why does the Serial.println in the if statement does not get executed?
Of course if I change it to if((unsigned char)(mil - start) >= period)
it works. but in all millis overflow questions, the guide says use this if (currentMillis - startMillis >= period) and you will be fine as long as both variables are defined as unsigned numbers

Any hint about this one?
Thanks

My suspicion is that the calculation is being done using integers but try this

void setup()
{
  Serial.begin(115200);
  byte start = 253;
  byte mil = 253;
  byte period = 3;
  mil++; // 254
  mil++; // 255
  mil++; // 0
  mil++; // 1
  mil++; // 2
  Serial.println(mil); // prints 2
  Serial.println(mil - start); // prints -251
  if ((byte)(mil - start) >= period)
  {
    Serial.println("Time passed");
  }
}

void loop()
{
}

Inside if(), mil - start will be promoted to int

UKHeliBob:
My suspicion is that the calculation is being done using integers

You mean "int"s - the variables already are integers

UKHeliBob:
My suspicion is that the calculation is being done using integers but try this

void setup()

{
 Serial.begin(115200);
 byte start = 253;
 byte mil = 253;
 byte period = 3;
 mil++; // 254
 mil++; // 255
 mil++; // 0
 mil++; // 1
 mil++; // 2
 Serial.println(mil); // prints 2
 Serial.println(mil - start); // prints -251
 if ((byte)(mil - start) >= period)
 {
   Serial.println("Time passed");
 }
}

void loop()
{
}

Works..
But if a cast is needed anyway,
A) Can I assume that for checking time elapsed with millis I should always cast the subtraction?
B) Doesn't it imply that in the "Using millis() for timing. A beginners guide" (thank you for this excellent one) a casting is missing in the examples and otherwise it actually won't handle correctly the millis overflow?

TolpuddleSartre:
You mean "int"s - the variables already are integers

I do

B) Doesn't it imply that in the "Using millis() for timing. A beginners guide" (thank you for this excellent one) a casting is missing in the examples and otherwise it actually won't handle correctly the millis overflow?

If all the terms are unsigned long, then no casts are necessary.

AWOL:
If all the terms are unsigned long, then no casts are necessary.

Thanks for replay.
Look at my example please
They are all unsigned char:
unsigned char start = 253;
unsigned char mil = 253;
unsigned char period = 3;

and yet, comparison fails

Try printing sizeof(mil - start) and you will see that it takes 2 bytes. The calculation has been done as ints

yanivps:
Thanks for replay.
Look at my example please
They are all unsigned char:
unsigned char start = 253;
unsigned char mil = 253;
unsigned char period = 3;

and yet, comparison fails

You can't promote an unsigned long to an int, so arithmetic it automatically done as unsigned long.
This is not the case for an unsigned char.

arduino_new:
Inside if(), mil - start will be promoted to int

Just to be clear: If mil and start are smaller types, that is true. If they are larger types, the calculation is not done using ints.

Why the promotion to int anyway ?

UKHeliBob:
Why the promotion to int anyway ?

'cos that's what the standard says.

TolpuddleSartre:
'cos that's what the standard says.

I get that, but why ?

UKHeliBob:
I get that, but why ?

so it is written, so let it be done.

Consistency - that's what standards usually promote.

TolpuddleSartre:
Consistency - that's what standards usually promote.

and expected behavior

Consistency with what ?
Are unsigned ints promoted to unsigned longs in calculations for instance ?
You can never have enough standards

Expected behaviour ?
There is nothing expected about the behaviour.
Sure it is documented, but why was it implemented ?

UKHeliBob:
Expected behaviour ?
There is nothing expected about the behaviour.

Certainly there is. You can expect that the handling of promotion confirms to the standards, even though your intuition suggests some other handling!

BulldogLowell:
Certainly there is. You can expect that the handling of promotion confirms to the standards, even though your intuition suggests some other handling!

I will grant you that it is expected because it is documented, as I said, but why was it written that way ? It can't have been an accident.