Python ctype 递归结构

11 投票
3 回答
2611 浏览
提问于 2025-04-15 13:22

我开发了一个用C语言写的DLL(动态链接库),并且写了一个C++的测试程序,结果这个DLL运行得很好。

现在我想用Python来和这个DLL进行交互。我已经成功地隐藏了大部分用户自定义的C结构,但有一个地方我必须使用C结构。因为我对Python还比较陌生,所以可能会搞错。

我的想法是用Python的ctype模块重新定义一些结构,然后把变量传递给我的DLL。不过在这些类里,我有一个自定义的链表,里面包含递归类型,具体如下:

class EthercatDatagram(Structure):
    _fields_ = [("header", EthercatDatagramHeader),
                ("packet_data_length", c_int),
                ("packet_data", c_char_p),
                ("work_count", c_ushort),
                ("next_command", EthercatDatagram)]

这个方法失败了,因为在EthercatDatagram里面,EthercatDatagram还没有被定义,所以解析器返回了一个错误。

我应该如何在Python中表示这个链表,以便我的DLL能够正确理解呢?

3 个回答

-2

在你创建了_fields_之后,你需要以静态的方式来访问它。

class EthercatDatagram(Structure)
  _fields_ = [...]

EthercatDatagram._fields_.append(("next_command", EthercatDatagram))
1

之所以

EthercatDatagram._fields_.append(("next_command", EthercatDatagram))

不起作用,是因为创建描述符对象的机制(可以查看PyCStructType_setattro函数的源代码)只有在给类的_fields_属性赋值时才会被激活。仅仅把新字段添加到列表中是完全不会被注意到的。

为了避免这个问题,始终使用元组(而不是列表)作为_fields_属性的值:这样可以明确表示你需要给这个属性赋一个新值,而不是在原地修改它。

18

你几乎可以肯定需要把next_command声明为一个指针。因为在任何编程语言中,结构体里包含它自己是不可能的。

我想这就是你想要的:

class EthercatDatagram(Structure):
    pass
EthercatDatagram._fields_ = [
    ("header", EthercatDatagramHeader),
    ("packet_data_length", c_int),
    ("packet_data", c_char_p),
    ("work_count", c_ushort),
    ("next_command", POINTER(EthercatDatagram))]

撰写回答