Ctypes:解析参数和返回结果

0 投票
2 回答
518 浏览
提问于 2025-04-17 23:31

我第一次在Python中尝试使用ctypes这个库。我写了一个C语言文件,里面有一些方法可以用来计算点(和曲线)的旋转。我的代码是:

#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;
}

我用GCC编译了这个代码。

gcc -lm -shared lib.c -o lib.so

在我的Python代码中:

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

你能帮我解决以下问题吗:

  1. 如何用ctypes从Python中解析double数组?

  2. 如何将结果转换为double数组并在Python中返回?

谢谢!

2 个回答

1

@ebarr 提供了一个完整的代码示例。这里有一个稍微不同的版本。

为了让这个函数可以被多个线程调用,最好不要使用 static 变量:

#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);
}

你可以把 double P[2] 作为数组类型 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))

注意,你不需要显式地转换 angle(一个标量类型)。

3

所以关键在于确保ctypes知道你函数的参数类型是什么。

C语言那边没问题,但在Python这边,你需要为你的函数指定restypeargtypes

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)

使用这些值后,我得到了以下输出:

0.199995126141 0.00209437808939

撰写回答