From the Arduino-Reference I have the following information about integers:
"On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1)."
see int - Arduino Reference
I work with an Arduino Uno (ATMEGA328P) and an Arduino Mega (ATMEGA 2560) and tried to demonstrate that by a simple code:
void setup()
{
Serial.begin(9600);
}
void loop()
{
for (int i = 32760; i<=40000; i++)
Serial.println(i);
}
Running the code my Serial Monitor prints the following values:
I expected that i (which is an integer!) will start from -32768 once it becomes greater than 32767 but as you can see it doesn't. Has anyone an idea why there is no overload?
I don't have an Arduino available at the moment, but can see that this example
#include <stdio.h>
#include <stdint.h>
int main()
{
for (int16_t i = 32760; ; i++) {
printf("%d\n", i);
if (i < 0)
return -1; // stops here
if (i > 32777) return i;
}
return 0;
}
thank you for your message and sorry I didn't use code tags - this is my very first post here...
I get the same results using your code with volatile. The effect of volatile makes me very wonder and I have no explanation why the results change. However I will go on and try to find out why this happens.
making a variable volatile means that the compiler generates code that writes (& reads) the variable back from its registers to RAM after every change. IT does not optimize the performance by keeping an often used variable in its registers.
So it looks like the int i code in the for loop is optimized and stored in a 32 bit register which can hold values > 32767 and never written back. So it never sees it does not fit into a 16 bit var.
Still it is very strange and should imho not happen.
The compiler sees the 40000 value as not being able to fit in an int, so it uses 32 bit registers for the loop index, even though the initial value is typed as an int. Nothing strange about the results that either of you are seeing.
PaulS:
The compiler sees the 40000 value as not being able to fit in an int, so it uses 32 bit registers for the loop index, even though the initial value is typed as an int. Nothing strange about the results that either of you are seeing.
But why does the compiler not use 32 bit registers if I change int in uint8_t ? (see code below)
C:\Users\Rob\Desktop\WORK\Arduino\sketch_jan23c\sketch_jan23c.ino: In function 'void loop()':
C:\Users\Rob\Desktop\WORK\Arduino\sketch_jan23c\sketch_jan23c.ino:8:24: warning: comparison is always true due to limited range of data type [-Wtype-limits]
[color=red] for (int i = 32760; i<=32770; i++)
^ [/color]
So the compiler sees the limited range of the datatype... ? but decides to overrule?
Furthermore the compiler does the while correct - equivalent to for loop except for the scope of i
"undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses outside of array bounds, signed integer overflow, null pointer dereference, modification of the same scalar more than once in an expression without sequence points, access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful."
outsider:
Why I don't like to upgrade, you think everything is OK, then one day, GOTCHA!
Only a problem if you depend on Undefined, Unspecified, or Implementation-defined behavior.
The folks who were doing "i = i++;" found that out the hard way in the switch from 1.0 to 1.6. In 1.0 it works like "i++;" but in 1.6 it works like "i = i;"
It's been forever since I've so much as looked at a c/c++ spec, but I'm fairly certain it doesn't say ANYTHING about the internal representation of numbers. It almost certainly does not specify WHAT any number does when you perform an operation that results in exceeding its maximum value. So, what is shown here is almost certainly perfectly legal.
Counting on a specific behavior when you do something that doesnt make sense is a little silly, and will, at a minimum, be compiler and platform dependent.
Adding an extra read reference to i gives expected behavior
void setup()
{
Serial.begin(9600);
for (int i = 32760; i < 32800; i++) // uint16_t
{
Serial.println(i);
Serial.println(2*i); // enable/disable this line to see different loop behavior.
delay(100);
}
}
void loop(){}
Note this extra line does not assign any value to i so the compiler could just keep i optimized in a register.
But why does the compiler not use 32 bit registers if I change int in uint8_t ? (see code below)
Why should it? The initial value and termination value are 16 bit values. The compiler uses the smallest register type possible that will handle all the values.
PaulS:
Why should it? The initial value and termination value are 16 bit values. The compiler uses the smallest register type possible that will handle all the values.
OK, rephrase, why does it now uses a uint16_t type register for i while it otherwise uses an int16_t type register.
OK, rephrase, why does it now uses a uint16_t type register for i while it otherwise uses an int16_t type register.
The compiler saw that you wanted to use unsigned registers for the loop index, because your type was uint8_t. It also saw that 260 was a not a byte sized value, so it knew that the register size needed to be larger than 8 bits.
So, why wouldn't the compiler take note of both facts, and use unsigned 16 bit registers and generate appropriate instructions to use unsigned 16 bit processing?
PaulS:
The compiler saw that you wanted to use unsigned registers for the loop index, because your type was uint8_t. It also saw that 260 was a not a byte sized value, so it knew that the register size needed to be larger than 8 bits.
So, why wouldn't the compiler take note of both facts, and use unsigned 16 bit registers and generate appropriate instructions to use unsigned 16 bit processing?
For me that is simple, the compiler should not assume what I meant and autocorrect. It should beat me up if I provide stupid code, treat warnings as errors (as the warning of today is the error of tomorrow)
Otherwise it may add al those ; I forget after an evening of python or remove the ; when it should not be there e.g. after a for (...); break; forgotten in switch statements. etc.