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);

} 
5
  • 2
    Hint: Try "z = 255 * 255L;" or "z = 255 * (long) 255;" Commented Feb 5, 2019 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
    Commented Feb 5, 2019 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. Commented Feb 5, 2019 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. Commented Feb 5, 2019 at 11:03
  • @MikaelPatel You should answer the questions instead of writing snippets of them in the comment section.
    – pipe
    Commented Feb 5, 2019 at 12:57

2 Answers 2

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".

2
  • @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
    Commented Feb 5, 2019 at 10:39
  • wrap around doesn't sound right - but I know what you're saying Commented Feb 5, 2019 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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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