位运算用于标志位操作?

3

我看过一些使用位运算来创建选项/标志的代码。

例如,考虑来自ssl库的以下示例:

# 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

我不理解创建旗帜的这种系统如何运作,也不知道那些数字是怎么选择的。我研究了操作符的工作原理,但仍然感到困惑。
请问有人能够解释一下这个系统是如何运作的,并且适用的使用场景是什么吗?

3
欢迎来到SO!也许如果您尝试将这些数字转换为2进制,它们会更有意义。 - ggorlen
2个回答

6

当你用二进制查看数字时,它们似乎不那么随机 :)

>>> "{: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'

每个选项只是一个单独的比特位,可以被设置或清除。

2
除非你能够自动将十进制转换为二进制,否则打印标志群的十进制值是愚蠢的。根据你的喜好,以二进制、八进制或十六进制进行打印。
典型的用例是当你有一组相关的布尔值或者一组密集的二进制字段(例如机器码操作)时。将它们视为布尔值的紧凑记录。例如,你可能需要跟踪对象权限(读取、写入、修改、销毁)。你可以将其作为四个单独的布尔值,也可以简单地创建一个单一的值来编码所有四个值。例如,只有读取和销毁权限的用户“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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接