使用Ctypes从Python传递C结构体

3
我正在尝试调用一个使用结构体作为参数的C库函数。我该怎么做?我已经创建了类似于文档中所做的结构的Ctypes表示,但是直接传递它不起作用。我尝试找到例子,但是我找到的所有例子都是传递结构体指针。

2
你真的需要提供某种测试用例以及你遇到的错误。 - millimoose
据我所理解,问题在于该函数将整个结构体作为参数(例如 foo(struct mystruct bar))而不是指针。我不知道 ctypes 是否支持这种情况。您可以尝试通过传递一堆参数来模拟它,但这非常脆弱并且依赖于调用约定。最好编写一个 Cython 包装器或类似的东西。 - nneonneo
1
@nneonneo: 将普通结构体按值传递是可以的。问题在于,在x86-64上传递联合体、带位域的结构体和紧凑结构体,参见1657516576 - Eryk Sun
@eryksun:这是我的问题。我如何按值传递一个结构体?比如说,我想要传递的结构体是一个POINT,我该怎么做? - Adham
让我们称其为“Point”。将其放入函数指针的“argtypes”中,例如“lib.foo.argtypes = [Point]”。然后,“p = Point(10, 20); lib.foo(p)”传递这样的小结构体到栈上是合理的。通常对于更大的结构体,您需要一个指针,例如“lib.bar.argtypes = [POINTER(SomeBigStructure)]”。然后,“sbs = SomeBigStructure(); lib.bar(byref(sbs))”。 - Eryk Sun
2个回答

3

我有完全相同的问题。我有一个名为libxxxx.so的C文件和相应的.h文件。这就是全部了。在第一个.h文件中定义的几个函数原型需要在堆栈上传递结构体。该结构在第二个.h文件中定义。我查看了usb1 Python库包装器,每个结构都作为指向函数原型的指针传递。(有些甚至是指向指针的指针。)

我为此结构制作了一个包装器:

typedef struct _SE_ADDR{
   int slot;   /**< The index of the target slot. */
   int fpga;   /**< The index of the target FPGA. */
   int reg;    /**< The index of the target register. */
} SE_ADDR;

在Python包装模块中,我创建了一个类来表示这个结构体:
class SE_ADDR(Structure):
    _fields_ = [('slot', c_int),
                ('fpga', c_int),
                ('reg', c_int)]

SE_ADDR_p = POINTER(SE_ADDR) #Pointer to SE_ADDR required for se_waitForData_new

然后,在导入封装器后,我按照@picomancer上述的方式使用它:
addr = wrapper.SE_ADDR(0,0,0)

看起来这个有效。


3

没有看到您的代码,很难给出准确的答案,但我的猜测是您需要实例化这个数据结构。根据文档:

from ctypes import *

class POINT(Structure):
    _fields_ = [("x", c_int),
                ("y", c_int)]

point = POINT(10, 20)

最后一行创建了一个名为point的POINT结构实例。

如果您能显示结构定义,展示如何使用它以及任何错误信息,将会非常有帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接