如何管理 ctypes 中的嵌套结构?

Posted

技术标签:

【中文标题】如何管理 ctypes 中的嵌套结构?【英文标题】:How to manage nested structures in ctypes? 【发布时间】:2020-04-07 08:32:34 【问题描述】:

我有一个带有以下联合的 C++ 库:

typedef union DVersion

    uint32_t VMask;
    struct
    
        uint8_t Build;
        uint8_t Rev;
        uint8_t Min;
        uint8_t Maj;
    ;
DATA_VER;

还有一个结构体,其字段包含这个结构体

typedef struct DH

    uint16_t   Tok1;
    DATA_VER   DVersion;
    uint16_t   DataCount;
DataHeader

当我在 C++ 上使用这个 dll 时,它可以完美运行,在 C# 上也是如此。这样 DLL 就被验证了。

当我使用 ctypes 处理 Python 时,看起来字节数不对应。

我已经尝试过这些解决方案

解决方案 1:

class VER_Struct(Structure):
    _fields_ = [("Build", c_uint8),
                ("Rev",  c_uint8),
                ("Min",  c_uint8),
                ("Maj",  c_uint8)]

class DATA_VER(Union):
    _anonymous_ = ("u",)
    _fields_ = [("VMask", c_uint32, 32), 
                ("u",VER_Struct)]

class DataHeader(Structure):
    _fields_ = [("Tok1", c_uint16, 16),
                ("DVersion", DATA_VER),
                ("DataCount", c_uint16, 16)]

解决方案 2:

class DATA_VER(Union):
    _fields_ = [("VMask", c_uint32, 32), 
                ("Build", c_uint8),
                ("Rev",  c_uint8),
                ("Min",  c_uint8),
                ("Maj",  c_uint8)]

class DataHeader(Structure):
    _fields_ = [("Tok1", c_uint16, 16),
                ("DVersion", DATA_VER),
                ("DataCount", c_uint16, 16)]

在这两种情况下,Tok1 的值都正确,但 DVersion 和 DataCount 显示不正确。在我看来,由于嵌套结构,字节未对齐。

你能提示我我做错了什么吗?非常感谢您!

【问题讨论】:

也许检查什么是填充和对齐会有帮助? 谢谢,您知道我在哪里可以找到有关 ctypes 对齐的信息吗? 很高兴它有帮助,我以前从未使用过 ctypes :) 在这种解析器中,您可以根据经验法则记住检查接口上的两件事:1. padding ,2. endianness跨度> 【参考方案1】:

我发现了!

即使在 ctypes 文档中没有明确说明,包含 _pack_ = 1 在您的结构上。就我而言,它是:

class VER_Struct(Structure):
    _fields_ = [("Build", c_uint8),
                ("Rev",  c_uint8),
                ("Min",  c_uint8),
                ("Maj",  c_uint8)]

class DATA_VER(Union):
    _anonymous_ = ("u",)
    _fields_ = [("VMask", c_uint32, 32), 
                ("u",VER_Struct)]

class DataHeader(Structure):
    _pack_   = 1
    _fields_ = [("Tok1", c_uint16, 16),
                ("DVersion", DATA_VER),
                ("DataCount", c_uint16, 16)]

希望这对其他人有帮助!

【讨论】:

一般情况下,如果结构打包的话,只需要打包。 C++/C# 代码中是否有#pragma pack 或等效语句? 我遇到的麻烦是我使用的是外部 DLL,我只有 .H 和 Dll 通常.H文件会有结构定义和包装声明(如果有的话)。

以上是关于如何管理 ctypes 中的嵌套结构?的主要内容,如果未能解决你的问题,请参考以下文章

ctypes给扩展模块中的函数传递数组和结构体

ctypes 将另一个结构中的结构保存到文件中

ctype中的结构

在 Python/ctypes 中的结构内取消引用 C 函数指针

为 Python ctypes 中的结构实现 offsetof()

python ctypes:从指针变量中获取指向类型