using bitshift operators as increment/decrement in a for statement

Hello together,

I have a question regarding the increment/decrement part of “for” statements:
I have a situation in which it would be nice to use e.g. “i>>=1” instead of e.g. “i++” in a for statement. I have tried to do it with the code below:

for(byte var1 = 0xFF; var1 > 0x00; var1 >>= 1) {

...

}

Unfortunately the result is not the same as with the following code:

var1 = 0xFF;
for(int i = 0; i < 8; i++) {

...
var1 = var1 >> 1;

}

I have seen bitshift operators in as increment/decrement part of a for statement somewhen but I do not remember the programming language.

So my question to you:

  • Can I use bitshifting operators in C/C++as mentioned above?
  • If it should work: can you give me a hint why the results of the codes above are not the same?

Thanks in advance
Martin

ma787:
Unfortunately the result is not the same as with…

I can not see a difference there.

void setup() {
  Serial.begin(250000);
  Serial.print(F("Var1"));
  for (byte var1 = 0xFF; var1 > 0; var1 >>= 1) {
    inHex(var1);
  }
  Serial.println();
  Serial.print(F("Var2"));
  byte var1 = 0xFF;
  for (byte i = 0; i < 8; i++) {
    inHex(var1);
    var1 = var1 >> 1;
  }
  Serial.println();
}

void inHex(byte what) {
  Serial.write(' ');
  if (what < 16) {
    Serial.write('0');
  }
  Serial.print(what, HEX);
}
void loop() {}
Var1 FF 7F 3F 1F 0F 07 03 01
Var2 FF 7F 3F 1F 0F 07 03 01

Same as -

for ( uint8_t bit = 1 << 7; bit; bit >>= 1 ) {
    ...
}

lloyddean:
Same as -

for ( uint8_t bit = 1 << 7; bit; bit >>= 1 ) {


}

Not really.

void setup() {
  Serial.begin(250000);
  Serial.print(F("Var1"));
  for (byte var1 = 0xFF; var1 > 0; var1 >>= 1) {
    inHex(var1);
  }
  Serial.println();
  Serial.print(F("Var2"));
  byte var1 = 0xFF;
  for (byte i = 0; i < 8; i++) {
    inHex(var1);
    var1 = var1 >> 1;
  }
  Serial.println();
  Serial.print(F("Var3"));
  for ( uint8_t bit = 1 << 7; bit; bit >>= 1 ) {
    inHex(bit);
  }
  Serial.println();
}

void inHex(byte what) {
  Serial.write(' ');
  if (what < 16) {
    Serial.write('0');
  }
  Serial.print(what, HEX);
}
void loop() {}
Var1 FF 7F 3F 1F 0F 07 03 01
Var2 FF 7F 3F 1F 0F 07 03 01
Var3 80 40 20 10 08 04 02 01

Whandall, you have saved my evening ...

I was so concentrated in finding out if bitshifting as increment/decrement is possible that I have overseen one thing the whole afternoon: I have declared "var1" as an integer instead of a byte and did not see it :/ ...

I am sorry for bothering you with that issue - the solution is so stupid.

Martin

For your code with the print of the condition value perhaps not but for the original for loop it is!

ma787:
I have declared “var1” as an integer instead of a byte and did not see it :confused:

I see no difference for an int, so you probably made some other mistake. :wink:

void setup() {
  Serial.begin(250000);
  Serial.print(F("byte in for"));
  for (byte var1 = 0xFF; var1 > 0; var1 >>= 1) {
    inHex(var1);
  }
  Serial.println();
  Serial.print(F("shift byte "));
  byte var1 = 0xFF;
  for (byte i = 0; i < 8; i++) {
    inHex(var1);
    var1 = var1 >> 1;
  }
  Serial.println();
  Serial.print(F("shift int  "));
  int var2 = 0xFF;
  for (byte i = 0; i < 8; i++) {
    inHex(var2);
    var2 = var2 >> 1;
  }
  Serial.println();
}

void inHex(byte what) {
  Serial.write(' ');
  if (what < 16) {
    Serial.write('0');
  }
  Serial.print(what, HEX);
}
void loop() {}
byte in for FF 7F 3F 1F 0F 07 03 01
shift byte  FF 7F 3F 1F 0F 07 03 01
shift int   FF 7F 3F 1F 0F 07 03 01

An issue to be wary of is "sign extension". This matters when you right-shift a signed quantity.

Lets say you have an unsigned value 0b10001000 = 136

If you right-shift by one, this produces 0b01000100 = 68

Note that this does a division by two - peachy.

But let's say you have a [u]signed[/u] value 0b10001000 = -120

There are two ways to shift this right by one. The default, because it is a signed quantity, is to use sign extension. This means that the top bit gets kept the way it is. The result is 0b11000100 = -60

Note how this correctly gives an arithmetic division by 2. The problem is that this means that your loop will never terminate if the top bit of the starting quantity is set.

To fix this, use the C logical-shift-right operator, which is >>>, or >>>= and explicitly does a logical shift right even if the quantity being shifted is signed.

PaulMurrayCbr: But let's say you have a [u]signed[/u] value 0b10001000 = -120

There are two ways to shift this right by one. The default, because it is a signed quantity, is to use sign extension.

The result of right-shifting a negative value is implementation-defined. GCC uses sign extension.

To fix this, use the C logical-shift-right operator, which is >>>, or >>>= and explicitly does a logical shift right even if the quantity being shifted is signed.

There is no such thing in C/C++. You are thinking of some other language.