¿Cómo usar malloc y free con python ctypes?

Tengo una función en mi biblioteca de C, digamos runsim() que toma el puntero a struct repdata como uno de los argumentos, donde struct repdata es dado por

 struct repdata { int *var1; int *var2; int *var3; char *var4; double *var5; double *var6; int *var7; }; 

Cuando uso C exclusivamente, inicializo una variable de tipo struct repdata llamando a la función,

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

y luego rellena esta estructura a medida que avanza la simulación. Después de haber escrito los datos en un archivo, libero la memoria usando el estándar

 free(data.var1); free(data.var2); . . . free(data.var7); 

Quiero llamar a la función runsim() desde Python usando Python Ctypes. Para esto, necesito pasar un puntero a una variable (que es equivalente al tipo de struct repdata ) como uno de los argumentos runsim() . Supongamos que en Python he definido un equivalente de struct repdata de la siguiente manera.

 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)), ] 

¿Cuál es el equivalente de la función create_data_container que se muestra arriba en el lado de Python? Quiero inicializar una instancia de Repdata que se puede pasar al código C y tiene suficiente memoria para almacenar los datos de replicación. Y, una vez que se completa la simulación, ¿cómo libero la memoria de Python?

Estoy usando Ubuntu Linux 12.04.

Gracias de antemano por tu ayuda.

Puede asignar búferes utilizando ctypes y asignarlos a los punteros. Una vez que los objetos ctypes de Python no tengan referencias, se liberarán automáticamente. Aquí hay un ejemplo simple (con una DLL de Windows … no tenga a mano una máquina Linux, pero la idea es la misma) y un contenedor de Python.

create_string_buffer asigna un búfer de escritura que se puede pasar de Python a C y que los ctypes formarán como un char* .

También puede crear matrices de ctypes tipos de ctypes con la syntax:

 variable_name = (ctypes_type * length)(initial_values) 

xh

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

xc

 #include  #define DLL_EXPORTS #include "xh" 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); } 

x.py

 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) 

Salida

 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])