我正面临着着名的struct.pack的一个小角落。
情况如下:我有一个带有python的薄层包装器的dll。包装器中的一个python方法接受一个字节数组作为参数。该字节数组表示特定硬件总线上的寄存器。每条总线具有不同的寄存器宽度,通常为8,16和24位宽(在所有情况下,对齐都是相同的)。
调用此方法时,我需要将我的值(无论是什么)转换为8/16或24位的字节数组。使用struct.pack:
,使用8或16位这种转换相对容易byteList = struct.pack( '>B', regValue ) # For 8 bits case
byteList = struct.pack( '>H', regValue ) # for 16 bits case
我现在希望能够灵活地适应所有三种情况8/16& 24位。我可以使用前两行的混合来处理这三种情况;但我发现它很难看。
我希望这会奏效:
packformat = ">{0}B".format(regSize)
byteList = struct.pack( packformat, regValue )
但事实并非如此,因为struct.pack期望有相同数量的参数。
任何想法如何(整齐地)将我的寄存器值转换为任意数量的字节?
答案 0 :(得分:2)
你总是打包 unsigned 整数,只有big endian才能启动。看看打包时会发生什么:
>>> import struct
>>> struct.pack('>B', 255)
'\xff'
>>> struct.pack('>H', 255)
'\x00\xff'
>>> struct.pack('>I', 255)
'\x00\x00\x00\xff'
本质上,该值在开头用空字节填充。使用它有利于您:
>>> struct.pack('>I', 255)[-3:]
'\x00\x00\xff'
>>> struct.pack('>I', 255)[-2:]
'\x00\xff'
>>> struct.pack('>I', 255)[-1:]
'\xff'
如果你的价值太大,你现在不会得到例外,但它会极大地简化你的代码。您始终可以添加单独的验证步骤:
def packRegister(value, size):
if value < 0 or value.bit_length() > size:
raise ValueError("Value won't fit in register of size {} bits".format(size))
return struct.pack('>I', value)[-(size // 8):]
演示:
>>> packRegister(255, 8)
'\xff'
>>> packRegister(1023, 16)
'\x03\xff'
>>> packRegister(324353, 24)
'\x04\xf3\x01'
>>> packRegister(324353, 8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in packRegister
ValueError: Value won't fit in register of size 8 bits