I have a function in my C library, say runsim()
which takes pointer to struct repdata
as one of the arguments, where struct repdata
is given by
struct repdata {
int *var1;
int *var2;
int *var3;
char *var4;
double *var5;
double *var6;
int *var7;
};
When using C exclusively, I initialize a variable of type struct repdata
calling the function,
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);
}
and then fill this struct as simulation proceeds. After I have written the data to a file, I free the memory using the standard
free(data.var1);
free(data.var2);
.
.
.
free(data.var7);
I want to call the runsim()
function from Python using Python Ctypes. For this I need to pass a pointer to a variable (that is equivalent to the type of struct repdata
) as one of the runsim()
arguments. Suppose that in Python I have defined an equivalent of struct repdata
in the following manner.
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)),
]
What is the equivalent of create_data_container
function shown above on the Python side? I want to initialize an instance of Repdata which can be passed to C code and has sufficient memory for storing the replication data. And, once simulation is completed, how do I free the memory from Python?
I am using Ubuntu Linux 12.04.
Thanks in advance for your help.
You can allocate buffers using ctypes
and assign them to the pointers. Once the Python ctypes objects have no references they will be freed automatically. Here's a simple example (with a Windows DLL...don't have a Linux machine handy, but the idea is the same) and a Python wrapper.
create_string_buffer
allocates a writable buffer that can be passed from Python to C that ctypes
will marshal as a char*
.
You can also create writable arrays of ctypes
types with the syntax:
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])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With