You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从byte数组提取指定位范围比特时结果不符的问题排查

问题:从16字节byte数组中正确提取跨字节的比特值

我有一个16字节的byte数组,里面填充了各类跨字节边界的值,数据的二进制表示如下:

0011 | 0011 | 1110 | 1000 | 1100 | 1000 | 1100 | 1000 |
0100 | 1101 | 0010 | 1111 | 1010 | 0001 | 1111 | 1111 [ 0 - 63]

0000 | 0101 | 0000 | 0011 | 0000 | 0011 | 1110 | 1000 | 1100 | 1000 |
1100 | 1000 | 0000 | 0001 | 0010 | 1100 [64 -127]

需要提取的值对应的比特位置范围:

0-3 | 4-5 | 6-15 | 16-23 | 24-31 | 32 - 63 | 64-71 | 72-79 | 80-83 | 84-85 | 86-94 | 96-103 | 104-111 | 112-127


填充byte数组的代码

protected byte[] createMessageHeader(byte[] content) {
    int[] set = new int[128];
    set = intToBinary(set, 3, 3);
    set = intToBinary(set, 0, 5);
    set = intToBinary(set, 1000, 15);
    set = intToBinary(set, 200, 23);
    set = intToBinary(set, 200, 31);
    set = intToBinary(set, 1294967295, 63);
    set = intToBinary(set, 5, 71);
    set = intToBinary(set, 3, 79);
    set = intToBinary(set, 0, 83);
    set = intToBinary(set, 0, 85);
    set = intToBinary(set, 1000, 95);
    set = intToBinary(set, 200, 103);
    set = intToBinary(set, 200, 111);
    set = intToBinary(set, 300, 127);

    BitSet bitSet = binArrayToBitset(set);
    byte[] b1 = bitSet.toByteArray();

    for(int i = 0; i < b1.length; i++) {
        b1[i] = (byte) (Integer.reverse(b1[i]) >>> 24);
    }

    return b1;
}

protected int[] intToBinary(int[] binary, int val, int start) {
        // Number should be positive
        while (val > 0) {
            binary[start--] = val % 2;
            val = val / 2;
        }
        return binary;
    }
protected BitSet binArrayToBitset(int[] binArray) {
        BitSet set = new BitSet(128);

        for(int i = 0; i < binArray.length; i++) {
            if(binArray[i] != 0)
                set.set(i);
        }
        return set;
    }
//Convenience method to print binary representation of values
protected void toBinString(int[] set) {
        StringBuilder stringBuilder = new StringBuilder();
        for(int i = 0; i < set.length; i++) {
            if(i % 4 == 0)
                stringBuilder.append("|");
            if(i % 64 == 0)
                stringBuilder.append("\n");
            stringBuilder.append(set[i]);
        }
    }

当前提取代码及问题

我尝试了多种提取方法,最近的实现如下:

private int extractBits2(byte[] header, int start, int end) {
    BitSet bitSet = BitSet.valueOf(header);
    return (int) bitSet.get(start, end + 1).toLongArray()[0];
}

调用时:

int extracted = extractBits2(header, 6, 15)

返回值是0b00000011_10100000,但预期应该是0b0011 1110 1000(对应整数1000)。我哪里考虑漏了?需要实现正确提取指定位范围的值来做验证。

注意:除了一个timestamp是long类型,其余存储的值都是int类型。


问题原因及修复方案

问题出在字节反转操作和BitSet.valueOf()的比特顺序不匹配:

  1. 在createMessageHeader中,你对每个byte执行了Integer.reverse(b1[i]) >>> 24,这会反转单个字节内部的比特顺序(比如原字节00111110会变成01111100)。但BitSet.valueOf(byte[])默认按大端比特顺序解析数组——它将每个字节的最高位对应BitSet中索引较大的位,这和你存储时的反转操作完全冲突,导致比特位对应关系错乱。
  2. 你的intToBinary方法是从start位置**从右往左(低位到高位)**填充二进制位,逻辑本身和BitSet的索引规则一致,但字节反转破坏了这个对应关系。

修复后的提取方法

方法1:先还原字节反转再用BitSet解析

private int extractBits(byte[] header, int start, int end) {
    // 先还原每个字节的比特顺序
    byte[] reversedBytes = new byte[header.length];
    for (int i = 0; i < header.length; i++) {
        reversedBytes[i] = (byte) (Integer.reverse(header[i]) >>> 24);
    }
    // 用还原后的字节数组创建BitSet
    BitSet bitSet = BitSet.valueOf(reversedBytes);
    // 提取指定范围的位并转换为整数
    BitSet extractedBits = bitSet.get(start, end + 1);
    return extractedBits.isEmpty() ? 0 : (int) extractedBits.toLongArray()[0];
}

方法2:手动计算(更高效)

private int extractBitsManual(byte[] header, int start, int end) {
    int result = 0;
    int totalBits = end - start + 1;
    for (int i = 0; i < totalBits; i++) {
        int bitIndex = start + i;
        // 计算当前位所在的字节索引
        int byteIdx = bitIndex / 8;
        // 因为原字节被反转过,所以字节内的位索引是7 - (bitIndex % 8)
        int bitInByte = 7 - (bitIndex % 8);
        // 提取该位的值并设置到结果的对应位置
        int bit = (header[byteIdx] >> bitInByte) & 1;
        result |= (bit << i);
    }
    return result;
}

验证

调用extractBits(header,6,15)或extractBitsManual(header,6,15),即可得到预期的整数1000。


内容的提问来源于stack exchange,提问作者millerbill3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:00:57