4

所以我了解如何更改一个字节内的单个位,我不确定为什么我的特定代码不起作用。

public static void setBit(byte[] input, int position, int value) {
    int byteLocation = position / 8;
    int bitLocation = position % 8;
    byte tempByte = input[byteLocation];

    if (value == 0) 
    tempByte = (byte) (tempByte & ~(1 << bitLocation));
    else
    tempByte = (byte) (tempByte | (1 << bitLocation));

    input[byteLocation] = tempByte;
}

现在我一直在使用 64 位长的字符串“Testing1”对其进行测试,然后尝试设置位并显示值。它最多可以处理 46 位,然后在第 47 位,如果我尝试将其设置为 1,它会停止工作,但是可以正常使用 0。

以我的方式看不到错误,这是我测试它的方式

String test = "Testing1";

byte[] bytes = test.getBytes();

for (int i = 0; i < bytes.length; i++)
    System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");

setBit(bytes, 44, 1);
System.out.println();
for (int i = 0; i < bytes.length; i++)
    System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");

以下是我尝试将第 47 位更改为 1 时的输出

01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 01101110[5] 01100111[6] 00110001[7] 
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 11111111111111111111111111101110[5] 01100111[6] 00110001[7] 
4

5 回答 5

3

将格式更改为

Integer.toBinaryString(0xFF & bytes[i])

byte 需要被屏蔽,因为它是符号扩展的,而不是零扩展的,到 32 位 int

于 2013-04-10T04:37:11.277 回答
2

问题是您正在相关字节中设置符号位。因此,该字节现在具有负值。你调用Integer.toBinaryString(),它接受一个 int 作为它的参数,而不是一个字节。字节被提升为 int,并且它正确评估了以下值:

11101110

到它的等效整数:

11111111111111111111111111101110
于 2013-04-10T04:39:33.540 回答
0

I haven't looked at it in too much detail but I think the problem with the one bite is that it's being extended to an int (Since it's signed, the 1 extends to a negative int).

Just take the last 8 characters of the string and it will work fine.

于 2013-04-10T04:44:28.660 回答
0

我使用^(xor)使您的方法更小

public static void setBit(byte[] input, int position, int value) {
    int byteLocation = position / 8;
    int bitLocation = position % 8;
    input[byteLocation] = (byte) (input[byteLocation] ^ (byte) (1 << bitLocation));
}
于 2013-04-10T04:38:04.860 回答
0

我最近不得不做这样的事情。
我设法通过(大量使用白板但是..)将原始位右移到我想要替换的 LSB 的位置并使所有位包括我想要替换的 MSB 1 来实现它。
然后,我将我想要的位与我想要替换的位相加,左移与我右移相同的数字,将结果与原始结果进行或运算,并通过替换的异或掩码进行与运算。(喘口气,我会试着解释)

假设我有字节:
1111 1010 0001 1001

,我想用 0001 替换半字节 1010 以产生:

1111 0001 0001 1001。

我实现这一点的操作是:

1) 右移 8 以产生:
0000 0000 1111 1010

2) 或掩码 0xf (1111) 产生:
0000 0000 1111 1111

3) 并将 0001 替换为 0000 0000 1111 1111 以产生:
0000 0000 0001

000 ) 左移 8 以产生:
0000 0001 0000 0000

5) 将掩码移动 LSB 位置并与全字节异或

1111 1111 1111 1111
0000 1111 0000 0000
================ ==
1111 0000 1111 1111

6) AND 异或,移位掩码与原始产生:

1111 0000 0001 1001
1111 0000 1111 1111
==================
1111 0000 0001 1001

7) 或上述结果与替换:

1111 0000 0001 1001
0000 0001 0000 0000
===================
1111 0001 0001 1001 <<最终结果
==================


在java中,这导致函数:

public long overwriteBits(long overwrite, long with, long shift, long mask)
{
    return ((((overwrite >> shift) | mask) & with) << shift) | (overwrite & (~0 ^ (mask << shift)));
}

其中“覆盖”是原始数据,“与”是您想要代替“移位”位置的位的位,掩码是一系列具有相同替换长度的正位。

要执行上述操作,我会调用(在 sudo 中):
overwriteBits(1111 1010 00011001, 0001 , 8, 1111)

我想提一下,以上内容可用于替换任何原语中的位,不需要字节数组。eg Replacing 11 bits, as below:

1101001010101101 1111 0101 101 001101
with 1010 1010 101

overwriteBits(1101001010101101 1111 0101 101 001101 , 1010 1010 101, 6 , 11111111111)

1101001010101101 1111 0101 101 001101
1101001010101101 1010 1010 101 001101

覆盖位(1789785421l,1365l,6,0x7FF)

于 2014-06-28T05:56:47.793 回答