Python3 ctypes 实现将指针数据复制到自定义Structure结构体的通用方法
实现方法
你可以用ctypes原生的内存操作能力完成需求,以下是两种常用实现方案,还可以封装为通用方法适配所有自定义Structure类型:
方案1:内存拷贝(推荐,生成独立实例不影响原数据)
用ctypes.memcpy直接把Message.data指向的内存内容拷贝到目标结构体实例的地址,提前加长度校验避免内存越界:
# 先导入所需的ctypes工具函数 from ctypes import sizeof, memcpy, addressof # 长度校验 if p.msg.data_len < sizeof(EventID): raise ValueError(f"数据长度不足:目标结构体需要{sizeof(EventID)}字节,实际仅返回{p.msg.data_len}字节") # 执行拷贝 eid = EventID() memcpy(addressof(eid), p.msg.data, sizeof(eid))
拷贝完成后可以直接访问eid的字段验证结果:
print([hex(b) for b in eid.recent_addition_timestamp]) # 输出 ['0x88', '0x29', '0xfd', '0x60'],和采样数据完全匹配
方案2:指针强制转换(无额外拷贝,适合只读场景)
如果不需要独立的结构体副本,只是要读取数据,可以直接把c_uint8类型的指针强制转为目标结构体类型的指针,直接读取内容即可:
from ctypes import cast, POINTER eid = cast(p.msg.data, POINTER(EventID)).contents
注意:该方案得到的eid直接指向原p.msg.data的内存地址,修改eid的字段会同步改动原data的内容,不需要修改原数据的场景优先用方案1。
通用方法封装
可以把以上逻辑封装为通用函数,适配任意自定义Structure类型:
from ctypes import sizeof, memcpy, addressof, cast, POINTER def buffer_to_struct(data_ptr, data_len, target_struct, copy_mode:bool = True): """ 将uint8指针指向的二进制数据转为自定义Structure实例 :param data_ptr: POINTER(c_uint8) 类型的数据源指针 :param data_len: 数据源实际有效长度 :param target_struct: 目标Structure类(注意是类不是实例) :param copy_mode: 是否拷贝内存,True返回独立副本,False直接复用原内存 """ required_size = sizeof(target_struct) if data_len < required_size: raise ValueError(f"数据长度不足,目标结构体需要{required_size}字节,实际仅{data_len}字节") if copy_mode: inst = target_struct() memcpy(addressof(inst), data_ptr, required_size) return inst else: return cast(data_ptr, POINTER(target_struct)).contents
调用示例:
# 拷贝副本模式 eid = buffer_to_struct(p.msg.data, p.msg.data_len, EventID) # 复用原内存模式 eid_ref = buffer_to_struct(p.msg.data, p.msg.data_len, EventID, copy_mode=False)
内容的提问来源于stack exchange,提问作者TheDude
相关产品推荐
相关产品推荐

