我在Linux系统上从Python调用C共享库。
我遇到的问题是C库中的函数将一个指向结构的指针作为参数。然后mallocs内存为一个结构数组,用数据填充数组并返回。所以我把函数定义为
from ctypes import *
class myStruct(Structure):
_fields_ = [("id", c_uint), "name", c_char*256)]
library.func.argtypes = [POINTER(myStruct)]
然后我这样称呼它:
Myfoo = myStruct
Foo = pointer(Myfoo)
Bar = library.func(Foo)
for i in range(Bar):
print("id = %u, name = %s" % (Foo[i].id, Foo[i].name))
Bar包含由func分配的结构数。
无论我做什么,我都无法从Foo中获取任何数据。几个月来,我尝试了多种不同的变体。我可以查看来自C库的日志,我知道它正在获取数据并将其返回,但我似乎找不到从Python中提取数据的方法。
有什么想法吗?
答案 0 :(得分:5)
如果我从问题中的评论中得到'func'原型,那么应该这样做:
#include <stdlib.h>
#include <stdio.h>
struct Foo
{
unsigned int id;
char name[256];
};
__declspec(dllexport) int func(struct Foo **ppFoo)
{
int i;
struct Foo *foo = malloc(5 * sizeof(struct Foo));
for(i=0;i<5;i++)
{
foo[i].id = i;
sprintf_s(foo[i].name,_countof(foo[i].name),"Name#%d",i);
}
*ppFoo = foo;
return 5;
}
from ctypes import *
dll = CDLL('x')
class Foo(Structure):
_fields_ = [
('id',c_uint),
('name',c_char*256)]
pfoo = POINTER(Foo)()
count = dll.func(byref(pfoo))
for i in xrange(count):
print pfoo[i].id,pfoo[i].name
0 Name#0
1 Name#1
2 Name#2
3 Name#3
4 Name#4
请注意,您仍然需要free
以某种方式分配内存......
答案 1 :(得分:4)
好的,那只需要一些小的更新。
首先,您的参数声明已关闭,但这可能无关紧要。就python-c值转换机制而言,指针是指针。最准确的是POINTER(POINTER(myStruct))
,但为了简单起见,我们只使用:
library.func.argtypes = [c_void_p]
接下来,您不需要为您的参数创建一个myStruct
实例来指出;你只需要一个有效的指针,以及指向的指针。 func
将分配实际的myStruct
个实例。所以让我们从:
Foo = ctypes.POINTER(myStruct)()
现在我们可以打电话给它。我们有一个myStruct*
,但我们会传递指针,因此func
可以更改它。我们不需要构造一个完整的其他指针对象,因此我们将使用较轻的byref
:
Bar = library.func(byref(Foo))
现在您可以遍历Foo[i]
。
for i in range(Bar):
print("id = %u, name = %s" % (Foo[i].id, Foo[i].name))