问题
Given a simple C file:
#include <stdio.h>
typedef struct point {
int x;
int y;
} POINT;
POINT get_point()
{
POINT p = {1, 2};
return p;
}
And I have a simple python file:
from ctypes import *
import os
lib_name = '/testlib.so'
test_lib = CDLL(os.getcwd() + lib_name)
class POINT(Structure):
_fields_ = [('x', c_int),
('y', c_int)]
# Sets p1 to the integer 1
p1 = test_lib.get_point()
# Sets p2 to the struct POINT with values {1, 0}
p2 = POINT(test_lib.get_point())
How can I set my returned value to the struct POINT
with values {1, 2}
?
回答1:
What you ar asking is nto the sole problem in your example. Just to answer just what you asked first: you have to annotate the C function return type, so that ctypes know it is a memory address - otherwise it is a (4 byte) integer by default (while in any 64 bit OS, pointers are 8 bytes long).
Then you can create Python side POINT structures by using the (hidden) "from_address" method in your POINT class:
test_lib.get_point.restype = c_void_p
p = POINT.from_address(test_lib.get_point())
print(p.x, p.y)
Before that works, however, you have a more fundamental issue on the C side:
the POINT structure you declare on your example only exists while get_point
is running, and is deallocated afterwards. The code above would lead to a segmentation fault.
Your C code have to allocate memory properly. And also, you should take provisions to deallocate data structures you allocate in C - otherwise you will have memory leaks as each call to the function in C allocates more memory and you don't free that. (Notice that this memory won't be freed by itself when the Python POINT object goes out of scope).
Your C code could be like this:
#include <stdlib.h>
#include <stdio.h>
typedef struct point {
int x;
int y;
} POINT;
POINT *get_point()
{
POINT *p;
POINT initial = {1, 2};
p = malloc(sizeof(POINT));
*p = initial;
return p;
}
void free_point(POINT *p)
{
free(p);
}
And with this Python part:
from ctypes import *
import os
lib_name = '/testlib.so'
test_lib = CDLL(os.getcwd() + lib_name)
class POINT(Structure):
_fields_ = [('x', c_int),
('y', c_int)]
test_lib.get_point.restype = c_void_p
p1 = POINT.from_address( test_lib.get_point())
print (p1.x, p1.y)
test_lib.free_point(byref(p1))
del p1
everything should just work.
(just so that this answer is a complete ctypes example, I will add the GCC commands to build the testlib file:
gcc -c -fPIC test.c -o test.o
gcc test.o -shared -o testlib.so
)
来源:https://stackoverflow.com/questions/38661635/ctypes-struct-returned-from-library