【问题标题】:Byte shift inverse operation字节移位逆运算
【发布时间】:2011-11-30 19:28:49
【问题描述】:

我有这个代码

byte[] b = new byte[]{-33,-4,20,30};
System.err.println(Arrays.toString(b));

int x =  (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];

b = new byte[]{(byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)(x)};

System.err.println(Arrays.toString(b));

输出:

[-33, -4, 20, 30]
[-34, -4, 20, 30]

我不明白为什么这个操作不是逆运算。

【问题讨论】:

  • 会不会有数据丢失?

标签: java byte bit-manipulation bitwise-operators


【解决方案1】:

您的问题是不需要的符号扩展。

具体来说,b[1]-4,或者0xfc 符号扩展为0xfffffffc,然后左移为0xfffc0000。这具有将最高有效字节减 1 的效果。

试试:

int x =  ((b[0] & 0xff) << 24) +
         ((b[1] & 0xff) << 16) +
         ((b[2] & 0xff) << 8) +
          (b[3] & 0xff);

【讨论】:

    【解决方案2】:

    请忽略我之前的回答;这是完全错误的。

    我认为这里的问题是当你以这种方式组合位时:

    (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3]
    

    没有做你认为你正在做的事。特别是,假设b[1] 是负数(它是负数)。当 Java 进行位移时,它总是在进行位移之前将值提升为 int。这意味着b[1] 在升级时将如下所示:

    11111111 11111111 11111111 bbbbbbbb
    

    这里,前导 1 来自整数的带符号二进制补码表示,这使得负数由许多前导零表示。当你把这个数字上移时,你会得到

    11111111 bbbbbbbb 00000000 00000000
    

    如果您随后将这些位添加到(b[0] &lt;&lt; 24),其格式为

    aaaaaaaa 00000000 00000000 00000000
    

    你确实没有得到

    aaaaaaaa bbbbbbbb 00000000 00000000
    

    因为表示中的前导 1。要解决此问题,您需要在添加之前屏蔽符号位。具体来说,如果你改变了

    b[1] << 16
    

    (b[1] << 16) & 0x00FFFFFF
    

    然后你屏蔽掉得到的位

    00000000 bbbbbbbb 00000000 00000000
    

    所以现在当你添加两个值时,你会得到

    aaaaaaaa bbbbbbbb 00000000 00000000
    

    根据需要。

    因此,通过在适当的时间在适当的掩码中进行与运算来形成组合位的正确表达式:

    (b[0] << 24) + ((b[1] << 16) & 0x00FFFFFF) + ((b[2] << 8) & 0x0000FFFF) + (b[3] & 0x000000FF)
    

    我已经在我的系统上进行了测试,它似乎工作得很好。

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 2019-08-21
      • 2017-08-03
      • 1970-01-01
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      相关资源
      最近更新 更多