我有一个共享库和两个头文件。我能够通过使用 swig 创建绑定(bind)来使用该库。但是,swig 版本相当慢,而且我没有设法包含对 numpy 数组的支持。我现在尝试使用 ctypes 从 Python 调用库的函数。

第一个 header 包含一个 extern "C" block ,它通过宏导出 3 个函数(我无法使用)。 header 的简化版本如下所示:

... 
 
class Foo; 
typedef Foo* FOO_HANDLE; 
 
#if !defined(__cplusplus) 
#   error "C++ Compiler only" 
#endif 
 
extern "C" 
{ 
    APIPROTOTYPE_EXT( MakeAlgo, FOO_HANDLE, (void) ); 
 
    APIPROTOTYPE_EXT( DestroyAlgo, void, ( FOO_HANDLE ) ); 
 
    APIPROTOTYPE_EXT( AlgoProcess, void, ( FOO_HANDLE, StructOne *, StructTwo *) ); 
} 

通常,第一个函数 MakeAlgo 返回指向 Foo 类实例的指针,第二个函数 DestroyAlgo 销毁该实例,并且第三个函数 AlgoProcess 将两个结构作为输入并就地修改它们的一些值。

第二个 header 包含 StructOneStructTwo 的定义以及一些常量。 StructTwo 包含多个嵌套结构。

在Python中,我使用ctypes.Structure重写了第二个 header 中包含的所有结构。我不会在这里发布所有代码,但这是我如何定义嵌套结构的示例:

class StructTwo(Structure): 
    _fields_ = [("foo", StructFoo), 
                ("dummy8", c_short)] 
 
class StructFoo(Structure): 
    _fields_ = [("bar", c_uint), 
                ("reserv1", c_uint), 
                ("reserv2", c_uint)] 

然后我的 Python 代码如下所示(假设结构位于 structurals.py 文件中):

from ctypes import * 
from structures import StructOne, StructTwo 
 
libfoo = ct.cdll.LoadLibrary(path/to/so/library) 
 
makeAlgo = libfoo.MakeAlgo 
makeAlgo.restype = c_void_p 
makeAlgo.argtypes = [] 
 
destroyAlgo = libfoo.DestroyAlgo 
destroyAlgo.restype = None 
destroyAlgo.argtypes = [c_void_p] 
 
submit = libfoo.AlgoProcess 
submit.restype = None 
submit.argtypes = [c_void_p, POINTER(StructOne), POINTER(StructTwo)] 
 
handle = makeAlgo() 
 
one = bar.StructOne() 
two = bar.StructTwo() 
 
submit(handle, byref(one), byref(two)) 
print(two.foo.bar)  # unsigned int, should output 1, got 196611000 instead 
 
destroyAlgo(handle) 

创建指向 Foo 类的指针并提交输入后,我检查了其中一个结构中的一些值,但它与预期结果不匹配。例如,我知道库仅将其中一个字段设置为 0 或 1,但我得到了一些奇怪的结果,例如 196611000。

有人知道出了什么问题吗(也许有人有类似的问题)?这可能是我定义结构的方式吗?或者它可能是一个指向未正确处理的 C++ 类的指针?

编辑

我设法解决了最初的问题。看来我定义结构的方式不正确。嵌套结构应该通过引用传递,而不是上面的代码:

class StructTwo(Structure): 
    _fields_ = [("foo", POINTER(StructFoo)), 
                ("dummy8", c_short)] 
 
class StructFoo(Structure): 
    _fields_ = [("bar", c_uint), 
                ("reserv1", c_uint), 
                ("reserv2", c_uint)] 
 
# Then to initialize the nested structure 
foo = StructFoo() 
two = StructTwo(pointer(foo))  # has to be pointer() not byref() 

但是,现在要访问 StructFoo 的字段,我必须这样做:

print(two.foo.contents.bar) 

在实际代码中,我最多可能有 4 个嵌套级别。那么有没有更优雅的方式来访问他们的字段:

two.foo.contents.baz.contents.qux.contents.field_value 

请您参考如下方法:

我的编辑不正确。

问题是有些结构是位域结构,指定每个域的宽度解决了这个问题:

class StructTwo(Structure): 
    _fields_ = [("foo", StructFoo), 
                ("dummy8", c_short)] 
 
class StructFoo(Structure): 
    _fields_ = [("bar", c_uint, 1), 
                ("reserv1", c_uint, 8), 
                ("reserv2", c_uint, 16)] 

Bit-field structures in ctypes .


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!