6

我在 Linux 系统上从 Python 调用 C 共享库。

我遇到的问题是 C 库中的函数将指向结构的指针作为参数。然后它为结构数组分配内存,用数据填充数组并返回。所以我将函数定义为

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 中提取它的方法。

有什么想法吗?

4

2 回答 2

5

If I got the 'func' prototype right from your comment in the question, then this should do:

C Code

#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;
}

Python Code

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

Output

0 Name#0
1 Name#1
2 Name#2
3 Name#3
4 Name#4

Note you will still need to free the allocated memory somehow...

于 2012-05-21T03:57:25.703 回答
4

Ok, this just needs a few small updates, then.

First, your argument declaration is off, but that probably doesn't matter. A pointer is a pointer, as far as the python-c value translation machinery is concerned. Most accurate would be POINTER(POINTER(myStruct)), but to make things simpler, let's just use:

library.func.argtypes = [c_void_p]

Next, you don't need to bother creating a myStruct instance for your argument to point at; you just need a valid pointer, and a pointer to that. func will allocate the actual myStruct instances. So let's start with:

Foo = ctypes.POINTER(myStruct)()

Now we can call it. We have a myStruct*, but we'll pass a pointer to it so func can change it. We don't need to construct a whole other pointer object, so we'll use the lighter byref:

Bar = library.func(byref(Foo))

Now you can iterate through Foo[i].

for i in range(Bar):
    print("id = %u, name = %s" % (Foo[i].id, Foo[i].name))
于 2012-05-21T03:59:12.590 回答