标志位运算?

bitwise operations for flags?

我看过一些代码片段,它们使用按位运算来创建 options/flags。

例如,考虑 ssl library 中的以下示例:

# bitwise AND and NOT
ctx = ssl.create_default_context(Purpose.CLIENT_AUTH)
ctx.options &= ~ssl.OP_NO_SSLv3

# bitwise OR
client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
client_context.options |= ssl.OP_NO_TLSv1
client_context.options |= ssl.OP_NO_TLSv1_1

这些标志的数值:

>>> ssl.OP_NO_SSLv3.value
33554432
>>> ssl.OP_NO_TLSv1.value
67108864
>>> ssl.OP_NO_TLSv1_1.value
268435456

我不明白这种创建旗帜的系统是如何工作的,或者这些数字是如何选择的。我已经研究了运算符的工作原理,但我仍然很困惑。

有人可以解释一下这是如何工作的,以及适当的用例吗?

当您以二进制形式查看时,这些数字似乎不那么随机了:)

>>> "{:032b}".format(ssl.OP_NO_SSLv3.value)
'00000010000000000000000000000000'

>>> "{:032b}".format(ssl.OP_NO_TLSv1.value)
'00000100000000000000000000000000'

>>> "{:032b}".format(ssl.OP_NO_TLSv1_1.value)
'00010000000000000000000000000000'

>>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
... client_context.options |= ssl.OP_NO_TLSv1
... client_context.options |= ssl.OP_NO_TLSv1_1
>>> "{:032b}".format(client_context.options)
'10010110010100100000000001010100'

每个选项只是设置或清除的一个位。

除非你在头脑中自动将十进制转换为二进制,否则打印标志簇的十进制值是愚蠢的。根据您的喜好以二进制、八进制或十六进制打印。

典型的用例是当您有

  • 一组相关的布尔值。
  • 密集的二进制字段序列,例如机器代码操作。

将这些视为布尔值的打包记录。例如,您可能需要跟踪对象权限(读写修改销毁)。您可以将其作为四个独立的布尔值来执行此操作,或者简单地创建一个值来对所有四个进行编码。例如,只有读取和销毁权限的人 R--D 的权限值为 1001 或 0x9。

当您想检查特定权限时,您可以使用按位运算来屏蔽不需要的权限。例如:

r_mask = b'1000
w_mask = b'0100
m_mask = b'0010
d_mask = b'0001

现在,检查很简单。查看某人是否对某个对象具有读取权限:

if obj.permission & d_mask:
    # Allow operation

要更改值,您可以允许操作授予写入或修改权限:

if obj.permission & (w_mask | m_mask):

或者如果您是一个能记住访问代码的强硬派:

if obj.permission & b'0110':

当您处理小字段的打包记录时,例如机器代码或通信协议,从传输字中提取一个字段很有用。 例如,如果您需要从一条指令中获取操作码,您可以屏蔽除(比如说)5 个操作码位之外的所有操作码并将它们移动到单词的右边缘:

op_mask = 0x7c00                         # bits 30-26 hold the op code
opcode = (instruction & op_mask) >> 26   # Shift right 26 bits