使用0b1111_1111对一个字节进行按位运算是做什么的?

时间:2017-03-29 19:16:22

标签: java casting bit-manipulation

我有以下方法:

int convert3ByteChunkTo24Bits(final byte[] bytes) {
    int bitsFor3ByteChunk = 0;

    bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[0] & 0b11111111);

    bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
    bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[1] & 0b11111111);

    bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
    bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[2] & 0b11111111);

    return bitsFor3ByteChunk & 0b00000000_11111111_11111111_11111111;
}

该方法的目的是追加传递的字节并以int格式返回。这是我的测试方法:

void testConvert3ByteChunkTo24Bits() {
    final byte ca = (byte) 0xCA;
    final byte fe = (byte) 0xFE;
    final byte ba = (byte) 0xBA;

    final byte[] man = {ca, fe, ba};
    final int bytesIn24Bits = base64EncoderHelper.convert3ByteChunkTo24Bits(man);

    System.out.println(bytesIn24Bits);
}

结果输出为:

13303482

以二进制形式表示:

00000000110010101111111010111010

这是正确的,是以后的预期结果:

0xCA = 11001010
0xFE = 11111110
0xBA = 10111010

所以,到目前为止一切顺利。只有一件事我不明白,为什么我需要逻辑和

(bytes[0] & 0b11111111)

当我不进行按位和操作时,如果实现如下:

int convert3ByteChunkTo24Bits(final byte[] bytes) {
    int bitsFor3ByteChunk = 0;

    bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[0]);

    bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
    bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[1]);

    bitsFor3ByteChunk = bitsFor3ByteChunk << 8;
    bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[2]);

    return bitsFor3ByteChunk & 0b00000000_11111111_11111111_11111111;
}

结果将是:

00000000111111111111111110111010

我错过了什么?什么

bytes[0] & 0b11111111

修复此处? (我发现它有点试用 - 错误,但仍然好奇为什么它有效..)

3 个答案:

答案 0 :(得分:1)

它处理有符号字节。

byte[0]的值为0b10000000。这看起来对你和我来说都是128,但由于manual,它看起来像-128。在使用int的计算中使用该值时,它将被符号扩展为值为11111111111111111111111110000000的int,这是一个值为-128的int

为避免此问题,此代码按位0b11111111执行。这是一个整数运算,因此该字节隐式转换为int 11111111111111111111111110000000,但and将其转换为00000000000000000000000010000000,这是所需的128。

这是对two's complement arithmatic的臭名昭着的Java问题的攻击。<​​/ p>

答案 1 :(得分:1)

在:

bitsFor3ByteChunk = bitsFor3ByteChunk | (bytes[0] & 0b11111111);

bytes[0]首先扩展为int值(整数全部用两个补码表示)。然后,对于存储在0xFF中的byte这样的值,相应的int值将为0xFFFFFFFF。然后屏蔽它以保留低8位。

答案 2 :(得分:0)

人类可读的等价物只是

Byte.toUnsignedInt(b)

或者如果你真的想明确但效率低下:

b < 0?  b + 256: b

老实说,当jdk方法或简单数学存在同样的事情时编写类似的代码只是混淆,我希望编写这样的代码的人永远不会和其他人一起结束......除非他们在C语言或其他一些固有的低级别字节争论项目中编写设备驱动程序。