字节移位反向操作

问题描述:

我有这样的代码字节移位反向操作

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] 

我想不通为什么这个操作并不INVERS。

+0

有可能是数据丢失吗? –

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

具体地说,b[1]-4,或0xfc该符号扩展为0xfffffffc然后左移到0xfffc0000。这有递减最显著字节由效果1

尝试:

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

请忽略我以前的答案;这是完全错误的。

我觉得这里的问题是,当您撰写位以这种方式:

(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] << 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) 

我已经在我的系统上测试这一点,它似乎工作得很好。

希望这会有所帮助!