Python3中from_buffer_copy转ctypes Structure失败:缓冲区过小原因及解决
问题原因与解决方法
为什么结构体被对齐到28或32字节?
有两个核心原因:
c_ulong的平台差异性:c_ulong的大小依赖系统位数——32位系统下是4字节,64位系统下是8字节。你的IP结构体中src和dst使用c_ulong,在64位系统中这两个字段各占8字节,直接让结构体总大小从理论上的20字节变成28字节(前面字段累计12 + 8*2 = 28)。如果未设置正确的打包规则,编译器还会为对齐更大的字段自动填充字节,最终可能达到32字节。- 错误的打包设置:ctypes中
_pack_属性需要设置为整数(表示按多少字节对齐),而非布尔值True。_pack_ = True不会生效,结构体依然遵循默认对齐规则,产生额外填充字节。
如何禁用对齐并让结构体大小为20字节?
修改两点即可:
- 替换
c_ulong为固定4字节类型:IP地址是32位(4字节),用c_uint32代替c_ulong,确保在任何平台下都是4字节大小。 - 正确设置打包规则:将
_pack_ = 1,强制结构体按1字节对齐,禁用任何自动填充。
修改后的代码如下:
import ctypes from ctypes import c_ubyte, c_ushort, c_uint32 class IP(ctypes.Structure): _pack_ = 1 # 按1字节对齐,禁用填充 _fields_ = [ ("_ihl", c_ubyte, 4), ("version", c_ubyte, 4), ("tos", c_ubyte), ("len", c_ushort), ("id", c_ushort), ("offset", c_ushort), ("ttl", c_ubyte), ("protocol_num", c_ubyte), ("sum", c_ushort), ("src", c_uint32), # 用固定4字节类型替代c_ulong ("dst", c_uint32) ] def __new__(self, socket_buffer=None): return self.from_buffer_copy(socket_buffer)
修改后结构体大小会严格等于20字节,使用IP(raw_buffer[0:20])创建实例就不会报错了。
内容的提问来源于stack exchange,提问作者Marco Boehrs
相关产品推荐
相关产品推荐

