1

我想读取 4 个字节,它们是无符号 32 位整数的小端编码,并将值分配给 Java int

(是的,实际上我会使用“long”,但在这种情况下,我“知道”无符号值永远不会大到它会溢出二进制补码表示法中的有符号 int,并且它适合我的插图使用 int )。

有问题的 4 个字节编码值 '216' little-endian 样式:

0xD8000000

基本上我只需要将以下位模式填充到 Java int 中:

0x000000D8

下面的简单代码应该可以做到......并且对于前三个 '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;

但是,它搞砸了:

s = s | b1;

...因为 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();

...这对可读性很好,但使用了 8 个我宁愿放弃的方法调用。

谢谢!大卫。

4

1 回答 1

6

只需将& 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;

或者更简洁:

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);

(显然“左移 0”是不必要的,但它可以保持更高的一致性。)

于 2010-09-30T16:37:45.333 回答