字节移位反向操作
问题描述:
我有这样的代码字节移位反向操作
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。
答
你的问题是不需要的符号扩展。
具体地说,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)
我已经在我的系统上测试这一点,它似乎工作得很好。
希望这会有所帮助!
有可能是数据丢失吗? –