标志位运算?
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
我看过一些代码片段,它们使用按位运算来创建 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