sim*_*mon 4 java bit-manipulation
我正在尝试用 Java 读取二进制文件。我需要读取无符号 8 位值、无符号 16 位值和无符号 32 位值的方法。执行此操作的最佳(最快、最美观的代码)是什么?我在 C++ 中做到了这一点,并做了类似的事情:
uint8_t *buffer;
uint32_t value = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24;
Run Code Online (Sandbox Code Playgroud)
但在 Java 中,如果 buffer[1] 包含一个因左移结果为 int (?) 而设置了符号位的值,则会导致问题。不是在特定位置仅 OR:ing 0xA5,而是在 0xFFFFA500 或类似的内容中 OR:s,这会“损坏”两个顶部字节。
我现在有一个代码,如下所示:
public long getUInt32() throws EOFException, IOException {
byte[] bytes = getBytes(4);
long value = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
return value & 0x00000000FFFFFFFFL;
}
Run Code Online (Sandbox Code Playgroud)
如果我想转换四个字节 0x67 0xA5 0x72 0x50,结果是 0xFFFFA567 而不是 0x5072A567。
编辑:这很好用:
public long getUInt32() throws EOFException, IOException {
byte[] bytes = getBytes(4);
long value = bytes[0] & 0xFF;
value |= (bytes[1] << 8) & 0xFFFF;
value |= (bytes[2] << 16) & 0xFFFFFF;
value |= (bytes[3] << 24) & 0xFFFFFFFF;
return value;
}
Run Code Online (Sandbox Code Playgroud)
但是没有更好的方法吗?对于像这样的简单事情来说,10 个位操作似乎“有点”多了..(看看我在那里做了什么?)=)
更常规的版本首先将字节转换为整数的无符号值:
public long getUInt32() throws EOFException, IOException {
byte[] bytes = getBytes(4);
long value =
((bytes[0] & 0xFF) << 0) |
((bytes[1] & 0xFF) << 8) |
((bytes[2] & 0xFF) << 16) |
((long) (bytes[3] & 0xFF) << 24);
return value;
}
Run Code Online (Sandbox Code Playgroud)
不要纠结于位操作的数量,编译器很可能会将这些操作优化为字节操作。
另外,您不应该long仅仅为了避免符号而使用 32 位值,您可以使用int并忽略它在大多数情况下都是有符号的这一事实。看到这个答案。
更新:需要将最高有效字节强制转换为 long,因为否则其最高有效位将被移入 32 位整数的符号位,可能会使其为负数。