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

后端 未结 8 1709
挽巷
挽巷 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 06:58

    To be portable and avoid implementation defined behavior of right shifting of signed integers, do all shifting with unsigned.

    Follows is a variation on @harold answer. It does not shift by the bit width (which is UB) nor depend on 2's complement. No branching. If on a rare machine not using not 2's complement, could create a trap value.

    #if INT_MAX == 0x7FFF && UINT_MAX == 0xFFFF
      #define W 16
    #elif INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF
      #define W 32
    #else
      // Following often works
      #define W (sizeof (unsigned)*CHAR_BIT)
    #endif
    
    int TwosComplementArithmeticRightShift(int x, int shift) {
      unsigned ux = (unsigned) x;
      unsigned sign_bit = ux >> (W-1);
      y = (ux >> shift) | (((0-sign_bit) << 1) << (W-1-shift));
    return y;
    }
    

    or as a one-liner

      y = (((unsigned) x) >> shift) | (((0-(((unsigned) x) >> (W-1))) << 1) << (W-1-shift));
    

提交回复
热议问题