Why does right shifting negative numbers in C bring 1 on the left-most bits? [duplicate]

江枫思渺然 提交于 2019-11-27 18:45:22

问题


The book "C The Complete Reference" by Herbert Schildt says that "(In the case of a signed, negative integer, a right shift will cause a 1 to be brought in so that the sign bit is preserved.)"

What's the point of preserving the sign bit?

Moreover, I think that the book is referring to the case when negative numbers are represented using a sign bit and not using two's complement. But still even in that case the reasoning doesn't seem to make any sense.


回答1:


The Schildt book is widely acknowledged to be exceptionally poor.

In fact, C doesn't guarantee that a 1 will be shifted in when you right-shift a negative signed number; the result of right-shifting a negative value is implementation-defined.

However, if right-shift of a negative number is defined to shift in 1s to the highest bit positions, then on a 2s complement representation it will behave as an arithmetic shift - the result of right-shifting by N will be the same as dividing by 2N, rounding toward negative infinity.




回答2:


The statement is sweeping and inaccurate, like many a statement by Mr Schildt. Many people recommend throwing his books away. (Amongst other places, see The Annotated Annotated C Standard, and ACCU Reviews — do an author search on Schildt; see also the Definitive List of C Books on Stack Overflow).

It is implementation defined whether right shifting a negative (necessarily signed) integer shifts zeros or ones into the high order bits. The underlying CPUs (for instance, ARM; see also this class) often have two different underlying instructions — ASR or arithmetic shift right and LSR or logical shift right, of which ASR preserves the sign bit and LSR does not. The compiler writer is allowed to choose either, and may do so for reasons of compatibility, speed or whimsy.

ISO/IEC 9899:2011 §6.5.7 Bitwise shift operators

¶5 The result of E1 >> E2is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.




回答3:


The point is that the C >> (right shift) operator preserves1 the sign for a (signed) int.

For example:

int main() {
  int a;
  unsigned int b;

  a = -8;
  printf("%d (0x%X) >> 1 = %d (0x%X)\n", a, a, a>>1, a>>1);

  b = 0xFFEEDDCC;
  printf("%d (0x%X) >> 1 = %d (0x%X)\n", b, b, b>>1, b>>1);

  return 0;
}

Output:

-8 (0xFFFFFFF8) >> 1 = -4 (0xFFFFFFFC)                    [sign preserved, LSB=1]
-1122868 (0xFFEEDDCC) >> 1 = 2146922214 (0x7FF76EE6)      [MSB = 0]

If it didn't preserve the sign, the result would make absolutely no sense. You would take a small negative number, and by shifting right one (dividing by two), you would end up with a large positive number instead.

1 - This is implementation-defined, but from my experience, most compilers choose an arithmetic (sign-preserving) shift instruction.




回答4:


In the case of a signed, negative integer, a right shift will cause a 1 to be brought in so that the sign bit is preserved

Not necessarily. See the C standard C11 6.5.7:

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

This means that the compiler is free to shift in whatever it likes (0 or 1), as long as it documents it.



来源:https://stackoverflow.com/questions/17358445/why-does-right-shifting-negative-numbers-in-c-bring-1-on-the-left-most-bits

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!