6

Executing the following code always gives -511 as a result, I performed many tests, and it seems that results are correct from 0 * 0 to 181 * 181, beyond that, results are abnormal, I tried many types for the z variable (int, long, float) without success, any idea? I'm using the Arduino Uno.

long z = 0;

void setup() {

Serial.begin(9600);

}

void loop() {

  z = 255 * 255;
  Serial.println(z);
  delay(200);

} 
  • 2
    Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;" – Mikael Patel Feb 5 at 10:25
  • I did. @MikaelPatel I worked indeed, could you explain the reason behind this, and is there similar cases for other types? – Huskarnov Feb 5 at 10:32
  • 4
    This "bug" is as old as programming. When you write "255" compiler creates an "integer constant" with value of 255. When you multiply 255 by 255 you multiply two "integer constants" and by convention result of such multiplication is an "integer". Then you implicitly cast it to long when doing assignment. When you multiply "255" by "255L" you actually multiply "integer constant" by "long constant" and result of such multiplication is "long". You will see similar issue when you write float z = 1 / 5 result will be 0 because integer division results with integer that is later casted to float. – Filip Franik Feb 5 at 10:54
  • 3
    Ref: gcc.gnu.org/wiki/avr-gcc is all the information you need for the AVR GCC compiler. It all has to do with 1) number range of "int" for a given target, and 2) compiler evaluation of constant expressions. – Mikael Patel Feb 5 at 11:03
  • @MikaelPatel You should answer the questions instead of writing snippets of them in the comment section. – pipe Feb 5 at 12:57
12

No, this is not a bug. You are using a compile time constant expression which is signed int unless told otherwise. Therefore you can only represent numbers between -32768 and 32767. Your computation of 255 * 255 = 65025 exceeds the range. Thus you see an overflow. In the C/C++ standard the overflow of signed types is actually undefined behavior. That means that the compiler is allowed to do anything from showing the correct answer to halt and catch fire. Only unsigned types with a known size like uint16_t have a well-defined overflow behaviour. You should promote your right hand side computation to unsigned type like this:

z = 255U * 255U;

This way you tell the compiler your intention and don't land in "Undefined-Behaviour-Land".

  • @Juraj Right, I thought it was signed 16 bit just as int. But the latter is still true. Compile time constants are signed int, which is 16 bit. So the right side of the assignement is the problem. – Kwasmich Feb 5 at 10:39
  • wrap around doesn't sound right - but I know what you're saying – Jaromanda X Feb 5 at 11:37
0

Assuming long is 4 bytes, it should work.

However, if somehow a long type is only 2 bytes, or (more likely) you used another type or there is some wrong define/typedef, and it is a signed long (default if you do not used the unsigned keyword), the value range is -32,768 to 32,767 and 255 * 255 = 65,025 which is out of range.

So you can first try to use unsigned long.

  • long is -2,147,483,648 to 2,147,483,647 – Juraj Feb 5 at 10:30
  • With unsigned long the result becomes :4294966785. – Huskarnov Feb 5 at 10:40
  • Kwasmich's answer is correct – Juraj Feb 5 at 10:44
  • @Juraj - one short there :p – Jaromanda X Feb 5 at 11:36
  • 2
    it is not. Kwasmich explains – Juraj Feb 5 at 13:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.