How can I perform arithmetic right shift in C in a portable way?

后端 未结 8 1650
挽巷
挽巷 2020-12-19 06:29

We are writing an emulator where we need sign propagating right shift. The emulated system uses 2\'s complement numbers.

I read that the >> operat

8条回答
  •  时光说笑
    2020-12-19 07:09

    If you can have platform-specific code, you could test the existing >> operator (which may or may not do what you want for signed integers, but quite likely it will extend the sign). This is by far the simplest and most efficient solution for most platforms, so if portability is a concern I would just offer another solution as fallback. (I'm not altogether sure that there is any good way to test for this with the preprocessor, though, so the test would need to go into a build solution.)

    If you want to do it manually, you might do it by conditionally bitwise-ORing a mask of high bits, or in many cases:

    #define asr(x, shift) ((x) / (1 << (shift)) // do not use as is, see below
    

    The problem with the division solution is that the maximum divisor needed is not representable in the same signed type as x, so you would need to cast the types appropriately for the type of x and the necessary shifts (e.g., first to a larger type and then back since the result will fit).

    This solution follows from the fact that shifting binary numbers is equivalent (in an arithmetic sense) to multiplying and dividing by powers of two; this applies to both the division to simulate the arithmetic right shift, and the left-shift of 1 to obtain the power of two divisor.

    However, it is not exactly equivalent to the sign-extending right shift on two's complement machines, in particular if the division of a negative x results in zero: the true sign-extending shift should give -1 (all bits 1) on a two's complement machine - this would be -0 on one's complement. Similarly the negative result may be off by one with negative x, again due to difference between two's and one's complement. I would argue that the division gives the correct arithmetic result, but it does not match sign-extending results, and may thus be unsuitable for an emulator.

提交回复
热议问题