简体   繁体   English

Python使用ctypes自定义结构调用C共享库

[英]Python calling C Shared Library with ctypes custom structures

I'm calling a C shared library from Python on a Linux system. 我在Linux系统上从Python调用C共享库。

The problem I'm running into is the function inside the C library takes a pointer to a structure as an argument. 我遇到的问题是C库中的函数将一个指向结构的指针作为参数。 It then mallocs the memory for an array of structures, populates the array with data and returns. 然后mallocs内存为一个结构数组,用数据填充数组并返回。 So I've defined the function as 所以我把这个函数定义为

from ctypes import *
class myStruct(Structure):
    _fields_ = [("id", c_uint), "name", c_char*256)]

library.func.argtypes =  [POINTER(myStruct)]

Then I call it like so: 然后我这样称呼它:

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 contains the number of structures that were allocated by func. Bar包含由func分配的结构数。

No matter what I do, I can't get any data out of Foo. 无论我做什么,我都无法从Foo中获取任何数据。 I've tried multiple different variations on this for months. 几个月来,我尝试了多种不同的变体。 I can look at the logs from the C library and I know it's getting the data and returning it, but I can't seem to find a way to extract it from Python. 我可以查看来自C库的日志,我知道它正在获取数据并返回它,但我似乎找不到从Python中提取数据的方法。

Any thoughts? 有什么想法吗?

If I got the 'func' prototype right from your comment in the question, then this should do: 如果我从问题中的评论中得到'func'原型,那么应该这样做:

C Code C代码

#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 Python代码

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... 请注意,您仍然需要以某种方式free分配的内存...

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. 就python-c值转换机制而言,指针是指针。 Most accurate would be POINTER(POINTER(myStruct)) , but to make things simpler, let's just use: 最精确的是POINTER(POINTER(myStruct)) ,但是为了简单起见,我们只需使用:

library.func.argtypes = [c_void_p]

Next, you don't need to bother creating a myStruct instance for your argument to point at; 接下来,您不需要为您的参数创建一个myStruct实例来指出; you just need a valid pointer, and a pointer to that . 你只需要一个有效的指针,并指向 func will allocate the actual myStruct instances. func将分配实际的myStruct实例。 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. 我们有一个myStruct* ,但是我们会传给它一个指针,所以func可以改变它。 We don't need to construct a whole other pointer object, so we'll use the lighter byref : 我们不需要构造一个完整的其他指针对象,所以我们将使用更轻的byref

Bar = library.func(byref(Foo))

Now you can iterate through Foo[i] . 现在你可以迭代Foo[i]

for i in range(Bar):
    print("id = %u, name = %s" % (Foo[i].id, Foo[i].name))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM