-3

I’m currently playing around with bit manipulation in C, and I’m noticing that the right shift operator is not behaving as I anticipated. From what I understand, left shifts leave 0s behind as it shifts form the LSB, and right shifts leave 1s as it shifts from the MSB.

So I tried making a simple bit mask that looks like this: 110000

By creating an int 32>>1.

When I type in 32>>1, I don’t get 48 as expected, I get 16. Why?

Jens
  • 8,423
  • 9
  • 58
  • 78
  • 3
    There’s a difference between [arithmetic right-shift](https://en.wikipedia.org/wiki/Arithmetic_shift) and [logical right-shift](https://en.wikipedia.org/wiki/Logical_shift). If you want logical right-shift in C, consider: https://stackoverflow.com/questions/5253194/implementing-logical-right-shift-in-c#5253269 – Jens Oct 12 '18 at 22:59
  • 1
    Always post an [MCVE]. – jwdonahue Oct 12 '18 at 23:05
  • 3
    "... right shifts leave 1s as it shifts from the MSB" - that's just not true. For non-negative values right shift is defined as division by 2. So, 32 becomes 16, as it should. – AnT stands with Russia Oct 12 '18 at 23:11
  • 1
    32 is an `int`, perhaps 32-bit. 00000000-00000000-00000000-0010000 shift right is 00000000-00000000-00000000-00010000 or 16. Post a [mcve] for more details. – chux - Reinstate Monica Oct 13 '18 at 01:02

2 Answers2

2

The arithmetic right shift only shifts in ones if the high bit is currently 1.

Consider this program:

main() {
  int a, b;
  a = 32;
  b = a>>1;
  printf("a is %d 0x%08x; b is %d 0x%08x\n",a,(unsigned int)a,
         b,(unsigned int)b);
  a = -10;
  b = a>>1;
  printf("a is %d 0x%08x; b is %d 0x%08x\n",a,(unsigned int)a,
         b,(unsigned int)b);
}

If you run this, you will see:

a is 32 0x00000020; b is 16 0x00000010
a is -10 0xfffffff6; b is -5 0xfffffffb
Mac
  • 299
  • 2
  • 5
  • 1
    This causes undefined behaviour by using the wrong format specifier, `%x` requires an `unsigned int` operand – M.M Oct 12 '18 at 23:13
  • It is strictly undefined only as the code will reveal how signed integers are represented on the machine on which the code is run. For 99% of machines around today, they will be stored as two's complement numbers. In any case I have edited the code to cast the arguments to '%x' to "unsigned int", which avoids the warning; but has the same effect of revealing the underlying two's complement representation. – Mac Oct 15 '18 at 04:01
1

The most significant bit (MSB) that an arithmetic right-shift replicates is the high bit in the type being shifted, not the high bit in the value being shifted.

Thus, if you have a 32-bit int with value 32, the most significant bit of its value (1000002) is the bit in the 25 position. But the computer works with all 32 bits (000000000000000000000000001000002), and the most significant bit is the 0 in the 231 position.

That said, the behavior of >> with a negative left operand is implementation-defined. It may be arithmetic right shift, but it may be something else.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312