Битовая маскировка в Python - PullRequest
7 голосов
/ 14 декабря 2011

У меня есть байт (от другого поставщика), где потенциальные битовые маски выглядят следующим образом:

значение1 = 0x01 значение2 = 0x02 значение3 = 0x03 значение4 = 0x04 значение 5 = 0x05 значение 6 = 0x06 значение 7 = 0x40 значение 8 = 0x80

Я могу рассчитывать на ОДИН из значений от 1 до 6. И тогда значение7 может быть или не быть установлено. значение 8 может быть или не быть установлено.

Так что это законно: value2 | значение7 | ценности8 Это не законно: value1 | значение3 | value7

Мне нужно выяснить, установлено ли значение 7, установлено ли значение 8 и какое оставшееся значение.

У меня есть следующий код Python. Есть ли более элегантный способ сделать это?

value1 = 0x01
value2 = 0x02
value3 = 0x03
value4 = 0x04
value5 = 0x05
value6 = 0x06
value7 = 0x40
value8 = 0x80

def format_byte_as_bits(value):
    return format(value,'b').zfill(8)

def mask_bits_on_byte(byte,mask):
    inverse_of_mask = mask ^ 0b11111111
    return byte & inverse_of_mask

def parse_byte(byte):

    value7_set = byte & value7 == value7
    value8_set = byte & value8 == value8
    byte = mask_bits_on_byte(byte,value7)
    byte = mask_bits_on_byte(byte,value8)
    base_value = byte
    return value7_set,value8_set,base_value

# Example 1
byte = value3 | value7
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
print("value7_set = "+str(value7_set))
print("value8_set = "+str(value8_set))
print()

# Output:
# base_value = 3
# value7_set = True
# value8_set = False

# Example 2
byte = value5
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
print("value7_set = "+str(value7_set))
print("value8_set = "+str(value8_set))
print()

# Output:
# base_value = 5
# value7_set = False
# value8_set = False

# Example 3
byte = value1 | value7 | value8
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
print("value7_set = "+str(value7_set))
print("value8_set = "+str(value8_set))

# Output:
# base_value = 1
# value7_set = True
# value8_set = True

РЕДАКТИРОВАТЬ - Я ЛЮБЛЮ стекопотока. Так много полезных ответов, так быстро! Вы, ребята, потрясающие! Хотел бы я отметить все ответы. Но я, по крайней мере, дам всем право голоса!

РЕДАКТИРОВАТЬ2 - На основе ответов ниже, код упрощается до следующего:

value1 = 0x01
value2 = 0x02
value3 = 0x03
value4 = 0x04
value5 = 0x05
value6 = 0x06
value7 = 0x40
value8 = 0x80

def parse_byte(byte):
    return byte & value7, byte & 0x80, byte & 7

# Example 1
byte = value3 | value7
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
if value7_set: print("value7_set")
if value8_set: print("value8_set")
print()

# Example 2
byte = value5
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
if value7_set: print("value7_set")
if value8_set: print("value8_set")
print()

# Example 3
byte = value1 | value7 | value8
value7_set,value8_set,base_value = parse_byte(byte)
print("base_value = "+str(base_value))
if value7_set: print("value7_set")
if value8_set: print("value8_set")
print()

Ответы [ 4 ]

13 голосов
/ 14 декабря 2011

Большинство ваших value* констант на самом деле не являются битовыми масками, только value7 и value8. Я бы определил другую битовую маску для извлечения младших битов, поэтому у меня было бы всего три битовые маски:

mask0 = 0x07
mask1 = 0x40
mask2 = 0x80

Теперь ваша функция становится

def parse_byte(byte):
    return byte & mask2, byte & mask1, byte & mask0

Я не преобразовал результаты в bool - я не понимаю, почему это должно быть необходимо. При проверке возвращенного значения с помощью if оно все равно будет неявно преобразовано в bool.

Также обратите внимание, что

format(value,'b').zfill(8)

можно упростить до

format(value,'08b')
5 голосов
/ 14 декабря 2011

С учетом значения, такого как:

>>> x = 0b10001000

Вы можете узнать, установлены ли старшие биты с помощью:

>>> bit8 = bool(x & 0b10000000)
>>> bit7 = bool(x & 0b01000000)

Чтобы узнать, какой младший бит установлен, используйте словарь:

>>> bdict = dict((1<<i, i+1) for i in range(6))
>>> bdict[x & 0b00111111]
4
3 голосов
/ 14 декабря 2011

Вам не нужны две другие функции:

def parse_byte(byte):
    value7_set = byte & value7 == value7
    value8_set = byte & value8 == value8
    base_value =  byte & 7
    return value7_set,value8_set,base_value
1 голос
/ 14 декабря 2011

Это немного многословно, но прекрасно.Единственное изменение, которое я хотел бы сделать, это упростить parse_byte:

def parse_byte(byte):

     value7_set = byte & value7 == value7
     value8_set = byte & value8 == value8
     base_value = mask_bits_on_byte(byte,value7 | value8)
     return value7_set,value8_set,base_value  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...