简体   繁体   中英

Python calling C Shared Library with ctypes custom structures

I'm calling a C shared library from Python on a Linux system.

The problem I'm running into is the function inside the C library takes a pointer to a structure as an argument. It then mallocs the memory for an array of structures, populates the array with data and returns. 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.

No matter what I do, I can't get any data out of 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.

Any thoughts?

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...

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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