Dav*_*ock 1 java endianness bitwise-operators numeric-conversion
我想读取4个字节,它是无符号32位整数的小端编码,并将值赋给Java int
(是的,实际上我会使用'long',但在这种情况下我知道'无符号值永远不会那么大,它会以二进制补码表示法溢出一个带符号的int,并且它适合我的插图使用一个int ).
有问题的4个字节编码值'216'little-endian样式:
0xD8000000
Run Code Online (Sandbox Code Playgroud)
基本上我只需要将以下位模式填充到Java int中:
0x000000D8
Run Code Online (Sandbox Code Playgroud)
下面的简单代码应该这样做......对于前三个'0x00'字节,它成功:
byte b1 = din.readByte();
byte b2 = din.readByte();
byte b3 = din.readByte();
byte b4 = din.readByte();
int s = 0;
s = s | b4;
s = (s << 8);
s = s | b3;
s = (s << 8);
s = s | b2;
s = (s << 8);
s = s | b1;
return s;
Run Code Online (Sandbox Code Playgroud)
然而,它搞砸了:
s = s | b1;
Run Code Online (Sandbox Code Playgroud)
...因为b1的位是1101 1000,这是二进制补码表示法中的负数(-40),因为最高有效位是1.当Java在按位或运算符进行求值之前将b1扩展为int. ,-40编码为0xFFFFFFD8,这使我们天真的假设,即加宽int的前3个字节将为0.
所以我的策略搁浅了.但我该怎么做呢?甚至可以使用原始运算符解决这个问题(请给出解决方案),还是我们必须求助于类库?(我不会在我的正常编码中直接使用位和字节,所以我缺乏成语似乎应该是'每天'代码).
对于类库方法,以下片段得到了正确的结果:
ByteBuffer b = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).put((byte) 0xD8).put((byte) 0x00).put((byte) 0x00).put((byte) 0x00);
b.flip();
int s = b.getInt();
Run Code Online (Sandbox Code Playgroud)
...这对于可读性来说很好,但是使用了8个方法调用,我宁愿放弃.
谢谢!大卫.
只是包括& 0xff
每个字节为int的推广,以确保顶位被设置为0:
byte b1 = din.readByte();
byte b2 = din.readByte();
byte b3 = din.readByte();
byte b4 = din.readByte();
int s = 0;
s = s | (b4 & 0xff);
s = (s << 8);
s = s | (b3 & 0xff);
s = (s << 8);
s = s | (b2 & 0xff);
s = (s << 8);
s = s | (b1 & 0xff);
return s;
Run Code Online (Sandbox Code Playgroud)
或者更紧凑:
byte b1 = din.readByte();
byte b2 = din.readByte();
byte b3 = din.readByte();
byte b4 = din.readByte();
return ((b4 & 0xff) << 24)
| ((b3 & 0xff) << 16)
| ((b2 & 0xff) << 8)
| ((b1 & 0xff) << 0);
Run Code Online (Sandbox Code Playgroud)
(显然,"左移0"是不必要的,但它会保持一致性更高.)