why does this keep running beyond 32767

I thought the condition was no longer fulfilled if “a” jumps from +32767 to -32768 but it just keeps going on in the serial monitor.

/**********************************************************************************/

void setup() {
  Serial.begin(9600);
}
/**********************************************************************************/
void loop() {
  for (int a = 32500; a >= 0; a++) {
    Serial.print ("counter = ");
    Serial.println (a);
  }
}

What I see in the serial monitor

counter = 32762
counter = 32763
counter = 32764
counter = 32765
counter = 32766
counter = 32767
counter = -32768 <------ why does it not stop here a is <= 0?
counter = -32767
counter = -32766
counter = -32765
counter = -32764
counter = -32763
counter = -32762
counter = -32761

That’s a good question. It doesn’t seem to create a test at all…

000000d0 <loop>:
/**********************************************************************************/
void loop() {
  for (int a = 32500; a >= 0; a++) {
  d0:   c4 ef           ldi     r28, 0xF4       ; 244
  d2:   de e7           ldi     r29, 0x7E       ; 126
    Serial.print ("counter = ");
  d4:   60 e0           ldi     r22, 0x00       ; 0
  d6:   71 e0           ldi     r23, 0x01       ; 1
  d8:   8c e2           ldi     r24, 0x2C       ; 44
  da:   91 e0           ldi     r25, 0x01       ; 1
  dc:   0e 94 a1 02     call    0x542   ; 0x542 <Print::print(char const*)>
    Serial.println (a);
  e0:   4a e0           ldi     r20, 0x0A       ; 10
  e2:   50 e0           ldi     r21, 0x00       ; 0
  e4:   be 01           movw    r22, r28
  e6:   8c e2           ldi     r24, 0x2C       ; 44
  e8:   91 e0           ldi     r25, 0x01       ; 1
  ea:   0e 94 51 03     call    0x6a2   ; 0x6a2 <Print::println(int, int)>
  ee:   21 96           adiw    r28, 0x01       ; 1
  f0:   f1 cf           rjmp    .-30            ; 0xd4 <loop+0x4>

Interesting, I think it's a bug with whatever version of GCC is used actually for the Arduino compiler.

As shown in these two tests:

With C++ GCC 4.3.2 Same behavior as described in first post (try change a from 32765 to 32766 for another weird behavior!)

With C++ GCC 5.1 This one works as expected.

Can this be solved?

I can't test on Arduino right now, but on that ideone thing, changing a++ to a = a+1 solved it. Weird ;)

It'll work right if you make a "short" instead of "int", I think. Seems broken in 4.3.x, 4.8.x, and 4.9.x (all versions that Arduino has ever used!) Investigating...

using IDE 1.5.8.

... short a = 32700; a >= 0; a++ ...

only combining both suggestions works fine.

only changing "int" to "short" or only changing "a++" to "a = a + 1"

does not solve the problem.

using IDE 1.6.7.

only

for (short a = 32700; a >= 0; a++)

works fine

mixed result for different IDE version, confusing...

Worked fine for me (1.6.7) with just "short" In test examples (not within the ide), I couldn't get the "a=a+1" to make any difference.

What is the difference between short and integer, they look more or less the same?

They SHOULD be the same.

ArdLab_Gent: What is the difference between short and integer, they look more or less the same?

One is a datatype, the other is a classification of number.

/**********************************************************************************/

void setup() {
  Serial.begin(9600);
}
/**********************************************************************************/
void loop() {
  for (int a = 32500; a >= 0; a++) {
    Serial.print ("counter = ");
    Serial.println (a);
  }
}

I may be missing something…but…

set a to 32500.
“if” a is bigger than or equal to 0 (it always will be in this case…as it started as being defined as 32500!) and keep adding 1.

Int = 16 bits = -(2^16)/2 to (2^16)/2 = -32768 to 32768

counter = 32762
counter = 32763
counter = 32764
counter = 32765
counter = 32766
counter = 32767
counter = -32768    <------ why does it not stop here  a is <= 0?
counter = -32767
counter = -32766
counter = -32765
counter = -32764
counter = -32763
counter = -32762
counter = -32761

It has rolled over the max value of a signed int.

try declaring an unsigned int, max value = 0-2^16 = 0 to 65536.

It is like a buffer overflow. You want a 17th bit as a carry over…but only 16 are available for int_16. Causes panic. The carry is placed in the sign bit (17th bit) and you end up with the -11111111 as you’d expect.

The unsigned int has actually got the 16 bits + 1 (the “unused” sign bit). The 17th is not used as a sign bit so it can be rolled over and give the representation of the full 16bit range…

Or am I chatting rubbish?

Is the short somehow being used as ushort by the compiler…?

Johnny010: it always will be in this case...as it started as being defined as 32500!

The condition is re-evaluated every iteration. How would the loop know when to stop otherwise?

I may be missing something…

Indeed you are.

It has rolled over the max value of a signed int.

Exactly. As it has become negative, the test a >= 0 should fail.

try declaring an unsigned int, max value = 0-2^16 = 0 to 65536.

That just hides the problem. Generally, there is a need for signed numbers. We can’t just eliminate them.

ArdLab_Gent: What is the difference between short and integer, they look more or less the same?

You're confusing "int" with "integer" in your question - A "char" is an integer, but it is not an "int". Likewise, a "long" is an integer, but not an "int". A "short" is an integer and, depending on platform, may be exactly the same as an "int", but often won't be.

aarg: Indeed you are. Exactly. As it has become negative, the test a >= 0 should fail. That just hides the problem. Generally, there is a need for signed numbers. We can't just eliminate them.

This makes sense to me now. I see what the problem is.

So I got a pretty good answer over at AVRfreaks: http://www.avrfreaks.net/comment/1767746#comment-1767746 As you might have expected, if you've ever dealt with compiler folk, it's essentially "The behavior on integer overflow is defined to be undefined, so the compiler is free to do whatever it wants."

You can change the behavior with -fno-strict-overflow

So the compiler optimises the test out. Interesting and worth knowing.

That does not explain why int and short behave differently.

This should help explain why... https://www.google.com/search?q=undefined+definition