我正在用C编写一个代码求解器,导出到Windows DLL和DLL的Python包装器。我非常习惯Python,但我也是C和ctypes的完全初学者。
受此公认答案启发的修改解决方案如下:
c代码
/* my_clib.c */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct data {
int nr_steps;
double dt;
double* t;
double* x;
double t0, x0;
};
double fun_to_integrate(double t, double y){
return (y - t);
}
double rk4(double t, double y, double dt){
double k1 = dt * fun_to_integrate(t, y),
k2 = dt * fun_to_integrate(t + dt / 2, y + k1 / 2),
k3 = dt * fun_to_integrate(t + dt / 2, y + k2 / 2),
k4 = dt * fun_to_integrate(t + dt, y + k3);
return y + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
}
__declspec(dllexport) void my_fun(struct data* pointer){
int i;
double dt;
dt = pointer->dt;
pointer->t[0] = pointer->t0;
pointer->x[0] = pointer->x0;
for(i = 1; i < pointer->nr_steps; i++){
pointer->t[i] = dt*i + pointer->t0;
pointer->x[i] = rk4(pointer->t[i-1], pointer->x[i-1], dt);
}
}
与对应的Python文件
# my_python.py
import ctypes
import numpy as np
class DATA(ctypes.Structure):
_fields_ = [
('nr_steps', ctypes.c_int),
('dt', ctypes.c_double),
('t', ctypes.POINTER(ctypes.c_double)),
('x', ctypes.POINTER(ctypes.c_double)),
('t0', ctypes.c_double),
('x0', ctypes.c_double)]
def __init__(self):
self.nr_steps = 1000
self.dt = 0.00001
self.t0 = 0.
self.x0 = 2./3
self.t = (ctypes.c_double * self.nr_steps)()
self.x = (ctypes.c_double * self.nr_steps)()
class SOLVER(object):
def __init__(self):
self.clib = ctypes.CDLL('rk4.dll')
self.clib.my_fun.argtypes = [ctypes.POINTER(DATA)]
self.clib.my_fun.restype = None
def func(self, data_struc):
self.clib.my_fun(ctypes.byref(data_struc))
solver = SOLVER()
data = DATA()
solver.func(data)
在Windows 8下使用MinGW编译gcc -o -c my_clib.o my_clib.c
+ gcc -o rk4.dll -shared my_clib.o
一切运行正常,在最后一行solver.func()
之后,时间数据和溶液数据存储在data.t
和data.x
中。现在我需要从指针中访问计算出来的数据。这似乎不能直接做到。如果你访问type(data.x)
,你得到<class '__main__.LP_c_double'>
,但如果你试图访问type(data.x[i])
,你得到一个标准的double
。
每次我尝试例如plot(data.t, data.x)
或将其转换为np.array(data.t)
时,Python文件崩溃并且cmd冻结。然而,我认为x_python = [data.x[i] for x i in range(*number_of_elements*)]
工作,但它是非常慢的,如果数组很长。
我的问题是:访问c求解器中计算的数据的正确/最佳方法是什么?
同样,如果这不是从C传递数组到Python的最佳方式,还有什么其他替代方法适合这种应用程序?即,对于每一个时间步骤,或者可能在达到一些最终时间后,将解决方案(t, x)
(元组或两个数组)从C传递到Python?
从ctypes对象中访问int、long等类型的值,使用:
x = ctypes.c_int(123)
print x.value
所以,你可以遍历它们并创建你的数组。
同样,你可以传递一个清晰的C静态数组给Python,而不是使用结构体,并使用numpy的ctypes支持来获得numpy。
但是,我用这个结构明白你的意思。
您可以使用numpy.ctypeslib.as_array
。
从ctypes数组或ctypes指针创建numpy数组。numpy数组与ctypes对象共享内存。
numpy.ctypeslib.as_array(data.x, (data.nr_steps,)
使用不同形状的指针会有一个小问题。