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