使用ctypes转换字节串至VIDEO_IMAGE_STRUCT结构体结果不符,求排查
排查ctypes大端结构体转换错误
问题说明
使用Python的ctypes库将字节串转换为指定的大端无对齐C结构体时,magic_number和version字段解析结果与预期不符,需排查错误原因。
文档定义的结构体
// VIDEO_IMAGE_STRUCT:大端字节序、无对齐 struct { unsigned int magic_number = 0x5644454f; // 预期值:1447314767 unsigned short version; // 仅支持版本1 unsigned short image_mode; // Y8,Y16等格式 long long frame_number; // 帧计数(64位) int width; // 帧宽度(像素) int height; // 帧高度(像素) unsigned short endianness; // 0=小端,1=大端 unsigned short header_size; // 头部字节长度 unsigned short padding[2]; // 4字节填充(共两个ushort) } VIDEO_IMAGE_STRUCT;
错误代码
from ctypes import BigEndianStructure, c_int, c_uint, c_ushort, c_long, c_byte class VideoImageData(BigEndianStructure): _pack_ = 1 _fields_ = [ ("magic_number", c_uint), ("version", c_ushort), ("image_mode", c_ushort), ("frame_number", c_long), # 错误:对应文档的long long,应该用c_longlong ("width", c_int), ("heigth", c_int), # 拼写错误:应为height ("endianness", c_ushort), ("header_size", c_ushort), ("padding", c_ushort) # 错误:文档是padding[2],应该定义为(c_ushort * 2) ] if __name__ == "__main__": dstr = b'YATD\x02\x00@\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00\x08\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00' s = VideoImageData.from_buffer(bytearray(dstr))
异常结果
IN[1]: s.magic_number Out[1]: 1497453636 (预期值:1447314767) In[2]: s.version Out[2]: 512 (预期值:1)
错误原因与修复方案
1. 核心字段类型错误
文档中frame_number是64位长整型(long long),但代码中使用了c_long(对应C的long,通常为32位4字节),导致后续所有字段的偏移量整体错位,这是解析结果不符的主要原因。
- 修复:将
frame_number的类型改为c_longlong。
2. padding字段定义错误
文档中padding是unsigned short[2](两个无符号短整型,共4字节),但代码中只定义了单个c_ushort,结构体总长度计算错误,进一步加剧字段偏移。
- 修复:将
padding定义为(c_ushort * 2)。
3. 变量名拼写错误
代码中heigth应为height,虽然不影响解析,但建议修正以保持与文档一致。
4. 输入字节串的字节顺序问题
输入字节串的前4字节是b'YATD'(十六进制0x59415444),解析为大端无符号整数得到1497453636,但预期的magic_number是0x5644454F(对应字节b'VEDO')。如果确认输入字节串来源正确,需检查数据来源的字节序是否符合文档要求。
修复后的代码
from ctypes import BigEndianStructure, c_int, c_uint, c_ushort, c_longlong class VideoImageData(BigEndianStructure): _pack_ = 1 _fields_ = [ ("magic_number", c_uint), ("version", c_ushort), ("image_mode", c_ushort), ("frame_number", c_longlong), ("width", c_int), ("height", c_int), ("endianness", c_ushort), ("header_size", c_ushort), ("padding", c_ushort * 2) ] if __name__ == "__main__": # 替换前4字节为预期的magic_number对应字节,version字段改为00 01 dstr = b'VEDO\x00\x01@\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x02\x00\x00\x08\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00' s = VideoImageData.from_buffer(bytearray(dstr)) print(f"magic_number: {s.magic_number} (预期:1447314767)") print(f"version: {s.version} (预期:1)")
修复后的验证
修正后的结构体总长度为32字节,与文档定义一致;若输入字节串的前6字节为b'VEDO\x00\x01',解析后magic_number将为1447314767,version为1,符合预期。
内容的提问来源于stack exchange,提问作者Yury
相关产品推荐
相关产品推荐

