我的C库中有一个函数,比如说runsim()
,它指向struct repdata
作为参数之一,其中struct repdata
由
struct repdata {
int *var1;
int *var2;
int *var3;
char *var4;
double *var5;
double *var6;
int *var7;
};
当使用C exclusive时,我初始化一个调用函数
的struct repdata
类型的变量
struct repdata data;
void create_data_container(struct repdata *data, int len_data)
{
data -> var1 = malloc( sizeof(int) * len_data );
data -> var2 = malloc( sizeof(int) * len_data );
data -> var3 = malloc( sizeof(int) * len_data );
data -> var4 = malloc( sizeof(char) * len_data );
data -> var5 = malloc( sizeof(double) * len_data);
data -> var6 = malloc( sizeof(double) * len_data);
data -> var7 = malloc( sizeof(int) * len_data);
}
然后在模拟过程中填充此结构。在将数据写入文件后,我使用标准
释放内存free(data.var1);
free(data.var2);
.
.
.
free(data.var7);
我想使用Python Ctypes从Python调用runsim()
函数。为此,我需要将指向一个变量(相当于struct repdata
的类型)的指针作为runsim()
参数之一传递。假设在Python中我以下列方式定义了等效的struct repdata
。
import ctypes as C
class Repdata(C.Structure):
_fields_ = [
("var1", C.POINTER(C.c_int)),
("var2", C.POINTER(C.c_int)),
("var3", C.POINTER(C.c_int)),
("var4", C.POINTER(C.c_char)),
("var5", C.POINTER(C.c_double)),
("var6", C.POINTER(C.c_double)),
("var7", C.POINTER(C.c_int)),
]
上面在Python端显示的create_data_container
函数的等价物是什么?我想初始化一个Repdata实例,它可以传递给C代码,并有足够的内存来存储复制数据。并且,一旦模拟完成,我如何从Python中释放内存?
我使用的是Ubuntu Linux 12.04。
提前感谢您的帮助。
答案 0 :(得分:12)
您可以使用ctypes
分配缓冲区并将它们分配给指针。一旦Python ctypes对象没有引用,它们将自动释放。这是一个简单的例子(使用Windows DLL ...没有Linux机器,但想法是相同的)和Python包装器。
create_string_buffer
分配一个可写缓冲区,该缓冲区可以从Python传递给C ctypes
将作为char*
封送。
您还可以使用以下语法创建ctypes
类型的可写数组:
variable_name = (ctypes_type * length)(initial_values)
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
struct example {
char* data;
int len; // of data buffer
double* doubles;
int count; // of doubles
};
DLL_API void func(struct example* p);
#include <stdio.h>
#define DLL_EXPORTS
#include "x.h"
void func(struct example* p)
{
int i;
strcpy_s(p->data,p->len,"hello, world!");
for(i = 0; i < p->count; i++)
p->doubles[i] = 1.1 * (i + 1);
}
import ctypes
class Example(ctypes.Structure):
_fields_ = [
('data',ctypes.POINTER(ctypes.c_char)),
('len',ctypes.c_int),
('doubles',ctypes.POINTER(ctypes.c_double)),
('count',ctypes.c_int)]
def __init__(self,length,count):
self.data = ctypes.cast(ctypes.create_string_buffer(length),ctypes.POINTER(ctypes.c_char))
self.len = length
self.doubles = (ctypes.c_double * count)()
self.count = count
def __repr__(self):
return 'Example({},[{}])'.format(
ctypes.string_at(self.data),
','.join(str(self.doubles[i]) for i in range(self.count)))
class Dll:
def __init__(self):
self.dll = ctypes.CDLL('x')
self.dll.func.argtypes = [ctypes.POINTER(Example)]
self.dll.func.restype = None
def func(self,ex):
self.dll.func(ctypes.byref(ex))
d = Dll()
e = Example(20,5)
print('before:',e)
d.func(e)
print ('after:',e)
before: Example(b'',[0.0,0.0,0.0,0.0,0.0])
after: Example(b'hello, world!',[1.1,2.2,3.3000000000000003,4.4,5.5])