问题
I am experimenting for the first time with ctypes
in Python. I have written a C file which contains methods to make calculations so as to rotate points (and curves). My code is:
#include "math.h"
double * rotatePoint(double P[2], double angle) {
static double Q[2];
Q[0] = P[0] * cos(angle * M_PI/180);
Q[1] = P[1] * sin(angle * M_PI/180);
return Q;
}
I have compiled it with GCC
gcc -lm -shared lib.c -o lib.so
In my Python Code:
import ctypes
lib = ctypes.CDLL('lib.so')
def cRotatePoint(P):
#how I parse P in order to be understood by ctypes?
#.....
lib.rotatePoint(P)
#how can I return the array back?
#....
return P
Can you please help me on these:
Parse the double[] from Python with
ctypes
Convert the result into double[] in Python and return it
Thanks
回答1:
So the trick lies in making sure that ctypes knows what the argument types are for your function.
The C side of things is fine as is, but in the Python side you need to specify the restype
and argtypes
for your function:
import ctypes
lib = ctypes.CDLL('lib.so')
# let ctypes know the argument types
lib.rotatePoint.argtypes = [ctypes.POINTER(ctypes.c_double),ctypes.c_double]
# let ctypes know the return type
lib.rotatePoint.restype = ctypes.POINTER(ctypes.c_double)
def c_rotate_point(p,angle):
# convert arguments to appropriate ctypes type
p = (ctypes.c_double*2)(*p)
angle = ctypes.c_double(angle)
# call the function
retval = lib.rotatePoint(p,angle)
# here, retval has type LP_c_double object
# indexing this will dereference the underlying pointer giving the results
print retval[0],retval[1]
if __name__ == "__main__":
c_rotate_point((0.2,0.3),0.4)
For these values, I get the output:
0.199995126141 0.00209437808939
回答2:
@ebarr provided a complete code example. Here's a slight variation.
To allow calling the function from multiple threads, don't use static
variables:
#include "math.h"
void rotatePoint(double P[2], double angle, double Q[2]) {
Q[0] = P[0] * cos(angle * M_PI/180);
Q[1] = P[1] * sin(angle * M_PI/180);
}
You could pass double P[2]
as array type c_double * 2
:
import ctypes
from collections import namedtuple
ArrayType = ctypes.c_double * 2
Point = namedtuple('Point', 'x y')
lib = ctypes.CDLL('lib.so')
lib.rotatePoint.argtypes = [ArrayType, ctypes.c_double, ArrayType]
lib.rotatePoint.restype = None # void
def rotate_point(p, angle):
retval = ArrayType()
lib.rotatePoint(ArrayType(*p), angle, retval)
return Point(*retval)
if __name__ == "__main__":
print(rotate_point((0.2,0.3), 0.4))
Notice that you don't need to convert angle
(a scalar type) explicitely.
来源:https://stackoverflow.com/questions/22589487/ctypes-parse-arguments-and-return-results