获取字节字符串中特定位的值

8 投票
4 回答
27632 浏览
提问于 2025-04-15 21:19

在一个字节字符串中,有一个特定位置的字节代表了八个标志,每个标志对应字节中的一个比特位。如果一个标志被设置了,它的比特位就是1,否则就是0。举个例子,如果我有

b'\x21'

那么这些标志就是

0001 0101    # Three flags are set at indexes 0, 2 and 4
             # and the others are not set

那么,获取这个字节中每个比特位的值,知道某个特定的标志是否被设置,最好的方法是什么呢?(最好是用位运算来实现)

4 个回答

3

指定位掩码(可以了解一下维基百科上的位掩码):

FLAG_1 = 1  # 0000 0001
FLAG_2 = 2  # 0000 0010
FLAG_3 = 4  # 0000 0100
...

然后使用AND操作来检查某个比特位是否被设置(flags里包含你的字节):

if(flags & FLAG_1) { # bit 0 is set, example: 0001 0101 & 0000 0001 = 0000 0001

}
if(flags & FLAG_2) { # bit 1 is set, example: 0001 0101 & 000 0010 = 0000 0000

}
...

当然,你应该把FLAG_1等命名为一些有意义的名字,这要根据具体情况来定。比如可以用ENABLE_BORDER

更新:
我之前对你提到的哪些比特位被设置感到困惑,但在看了另一个回答后,我意识到你是从错误的方向数比特位。比特位是从右边开始,编号从零开始的。

7

x & 1, x & 2, x & 4, x & 8,等等

如果这些值大于0,那么表示第1位、第2位、第3位、第4位,等等的位是被设置为1的。

32

通常情况下,最低有效位是第0位,最高有效位是第7位。用这种说法,我们可以通过将1向左移动k位,然后进行按位与运算,来判断第k位是否被设置。如果按位与的结果不为零,那就说明第k位是1;否则,第k位就是0。所以:

def get_bit(byteval,idx):
    return ((byteval&(1<<idx))!=0);

这样就能正确判断字节中第0到第7位的值,从右到左(也就是从最低有效位到最高有效位,或者说从1的位到27 = 128的位)。

为什么这样有效
我觉得有必要解释一下为什么这样有效……

1<<0 等于 1 = 0000 0001
1<<1 等于 2 = 0000 0010
1<<2 等于 4 = 0000 0100

如你所见,1<<k等于2k,并且在我们关注的位上有一个1,而其他位置都是0。因此,和1<<k进行按位与运算的结果要么是0,要么是1<<k;如果我们关注的位是0,结果就是0(因为1和0的结果是0,而1<<k的其他位都是0)。如果我们关注的位是1,那么在那个位置上我们会得到1和1,而其他位置则是0和其他值。

撰写回答