Bitwise operations on 32 bit integers

Hi,

Is there a limitation on 32 bit operations using bitwise operators?

Can anyone please explain the change in output for i =15, why the x value changes so much for i =15 condition?

void setup() {
  Serial.begin(115200);
}


void loop() {
  for (int i = 0; i < 16; i++)
  {
    uint32_t x = 0;
    x = (uint32_t)(1 << (uint32_t)i);
    Serial.print("x is : ");
    Serial.println(x, BIN);
  }
}

use '1UL' in place on '1'

1 Like

That is an easy to make mistake.
The number 1 defaults to a integer type 'int', which is a 16-bit signed integer for the basic Arduino boards. You should shift a 32-bit value and not just a integer 'int'.

This is my solution, I shift a 'UL' (unsigned long) number:

void setup() 
{
  Serial.begin(115200);

  for (int i = 0; i < 16; i++)
  {
    uint32_t x = 1UL << i;
    Serial.print("x is : ");
    Serial.println(x, BIN);
  }
}

void loop() {}

In Wokwi:

[EDIT] Changed occording to @TheMemberFormerlyKnownAsAWOL in Reply 6

1 Like

By default, calculations are done with 16-bit integers (on an 8-bit microcontroller). At the moment that you shift the integer 1 15 times, the results is 1000 0000 which is a negative number.

You need to force the compiler to use an unsigned 32 bit number by using 1UL. Below a slightly modified version of your code

void setup() {
  Serial.begin(115200);
}


void loop() {
  for (int i = 0; i < 16; i++)
  {
    Serial.println(i);
    uint32_t x = 0;
    x = (uint32_t)(1UL << (uint32_t)i);
    Serial.print("x is : ");
    Serial.println(x, BIN);
  }
  delay(500);
}

Note:
Your original casts are not needed, x = 1UL << i; works as well.

1 Like

Thanks to all for explaining.
I understood it now.

sp. "The number 1 defaults to an int . You should shift a 32-bit integer type (e.g. uint32_t), and not just an int."

2 Likes

The width of the data shifted is set by the left hand value, not the righthand value (which never needs to be more than a byte anyway)

So use
1ul << i

Another way:

    uint32_t x = 1;
    x = x << i;
1 Like

And sure that we can do it with a one-liner :smiley:

I can only think of 'uint32_t x = 1ul << i;'

This is one case where the "the usual conversions" are not done. If you were using +, -, * or many other dyadic operators, the fact that one operand was 'uint32_t' would convert the other side from 'int' to 'uint32_t'. But not shifting.

I, too, found that out the hard way. :slight_smile:

1 Like

Interesting...

Nothing wrong with that (I think).