如何将 ctypes 转换为字节

S.R*_*S.R 4 python ctypes python-3.x

我想使用我定义的 ctype.Structure 作为 Python ( b'') 中的字节访问。

不知道是不是正确的方法?我需要向其他设备发送一个标头(它应该是无架构的)。

所以我将它定义为:

    class Header(ctypes.Structure):
    _pack_ = 2
    _fields_ = [
        ('version', c_uint8),
        ('additional_options', c_uint8),
        ('soft_version', c_uint16),
        ('compilation_time', c_uint8 * 6),
        ('crc', c_uint16)
    ]
Run Code Online (Sandbox Code Playgroud)

现在我需要计算CRC。从归档开始versioncompilation_time我有一个处理字节的函数。

所以对我来说,只需将 ctypes.Structure 转换为字节(b'')或直接访问内存并更改最后两个字节就可以了。

我试过使用struct但我没有找到pragma选项。

Mar*_*nen 5

struct 是你想要的:

>>> import struct
>>> fmt = struct.Struct('<BBH6s')
>>> data = fmt.pack(1,2,3,b'170207')
>>> data
b'\x01\x02\x03\x00170207'
>>> crc = <do your calculation>
>>> data += struct.pack('<H',crc)
Run Code Online (Sandbox Code Playgroud)

<意味着打包 little-endian 并且不会像 C 那样添加填充字节,所以没有_pack_必要。如果您需要 big-endian,请>改用。

我使用6s并传递了一个正确长度的字节字符串。如果您想传递原始字节,请使用6B并列出 6 个字节而不是一个字符串。

这是一个 ctypes 解决方案。我使用 crc32 是因为库中提供了一个用于演示目的。

from ctypes import *
from binascii import crc32

class Header(Structure):
    _pack_ = 2
    _fields_ = [
        ('version', c_uint8),
        ('additional_options', c_uint8),
        ('soft_version', c_uint16),
        ('compilation_time', c_uint8 * 6),
        ('crc', c_uint32)
    ]

h = Header(1,2,3)
h.compilation_time = (c_uint8 * 6)(*b'ABCDEF') 
b = bytes(h)[:Header.crc.offset] # convert struct to bytes and truncate CRC
print(b)
h.crc = crc32(b) # Set the correct CRC
b = bytes(h)     # convert whole struct to bytes
print(b)
Run Code Online (Sandbox Code Playgroud)

输出:

b'\x01\x02\x03\x00ABCDEF'
b'\x01\x02\x03\x00ABCDEF\xe7s\x85\xa6'
Run Code Online (Sandbox Code Playgroud)