2

on my Arduino, the following code produces output I don't understand:

void setup(){
  Serial.begin(9600);
  int a = 250;

  Serial.println(a, BIN);
  a = a << 8;
  Serial.println(a, BIN);
  a = a >> 8;
  Serial.println(a, BIN);


}

void loop(){}

The output is:

11111010
11111111111111111111101000000000
11111111111111111111111111111010

I do understand the first line: leading zeros are not printed to the serial terminal. However, after shifting the bits the data type of a seems to have changed from int to long (32 bits are printed). The expected behaviour is that bits are shifted to the left, and that bits which are shifted "out" of the 16 bits an int has are simply dropped. Shifting the bits back does not turn the "32bit" variable to "16bit" again.

Shifting by 7 or less positions does not show this effect.

I probably should say that I am not using the Arduino IDE, but the Makefile from https://github.com/sudar/Arduino-Makefile.

What is going on? I almost expect this to be "normal", but I don't get it. Or is it something in the printing routine which simply adds 16 "1"'s to the output?

Enno

2
  • Consider unsigned int for shifting if you want well defined behavior in c++. Commented Mar 16, 2016 at 19:36
  • Yep, that's what I resorted to after staring at this for an hour. Commented Mar 16, 2016 at 21:04

2 Answers 2

1

In addition to other answers, Integers might be stored in 16 bits or 32 bits depending on what arduino you have.

Sign up to request clarification or add additional context in comments.

Comments

1

The function printing numbers in Arduino is defined in /arduino-1.0.5/hardware/arduino/cores/arduino/Print.cpp

size_t Print::printNumber(unsigned long n, uint8_t base) {
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    unsigned long m = n;
    n /= base;
    char c = m - base * n;
    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

All other functions rely on this one, so yes your int gets promoted to an unsigned long when you print it, not when you shift it.

However, the library is correct. By shifting left 8 positions, the negative bit in the integer number becomes '1', so when the integer value is promoted to unsigned long the runtime correctly pads it with 16 extra '1's instead of '0's.

If you are using such a value not as a number but to contain some flags, use unsigned int instead of int.


ETA: for completeness, I'll add further explanation for the second shifting operation.

Once you touch the 'negative bit' inside the int number, when you shift towards right the runtime pads the number with '1's in order to preserve its negative value. Shifting to the left k positions corresponds to dividing the number by 2^k, and since the number is negative to start with then the result must remain negative.

1 Comment

Thanks for the comprehensive reply. I just couldn't wrap my head around this sort of "dynamic typing", and am glad to see it happens only at the printing stage.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.