I've been fooling with ctypes and have come across two problems:
Problem 1. I would like to build a cellComplex
using double*
arrays, but I want new_cellComplex
to accept an array of double*
's (along with a size_t
argument) rather than a fixed number of double*
's. With a fixed number the code looks like this (and it runs fine):
extern "C" {
void * new_cellComplex(double* p_x, double* p_y, double* p_z) {
std::vector< std::pair<double,double> > point;
point.push_back( std::make_pair(p_x[0],p_x[1]));
point.push_back( std::make_pair(p_x[0],p_x[1]));
point.push_back( std::make_pair(p_x[0],p_x[1]));
cellComplex<double>* cmplx = new cellComplex<double>(point);
return cmplx;
}
with Python code:
import ctypes
cellComplex_lib = ctypes.cdll.LoadLibrary('./cellComplex_lib.so')
cellComplex_lib.new_cellComplex.restype = ctypes.c_void_p
cellComplex_lib.new_cellComplex.argtypes = [ctypes.c_double*2,
ctypes.c_double*2,
ctypes.c_double*2]
p_x = (ctypes.c_double*2)(0.0,1.0)
p_y = (ctypes.c_double*2)(0.0,1.0)
p_z = (ctypes.c_double*2)(0.0,1.0)
cmplx = cellComplex_lib.new_cellComplex(p_x,p_y,p_z)
I would rather have the following (which segfaults):
extern "C" {
void * new_cellComplex(double** p, size_t dim) {
std::vector< std::pair<double,double> > point;
for (size_t i=0; i<dim; ++i) {
point.push_back( std::make_pair(p[i][0],p[i][1]));
}
cellComplex<double>* cmplx = new cellComplex<double>(point);
return cmplx;
}
}
With Python code:
import ctypes
dim = 3
cellComplex_lib = ctypes.cdll.LoadLibrary('./cellComplex_lib.so')
cellComplex_lib.new_cellComplex.restype = ctypes.c_void_p
cellComplex_lib.new_cellComplex.argtypes = [(ctypes.c_double*2)*dim,
ctypes.c_size_t]
p_x = (ctypes.c_double*2)(0.0,1.0)
p_y = (ctypes.c_double*2)(0.0,1.0)
p_z = (ctypes.c_double*2)(0.0,1.0)
p = ((ctypes.c_double*2)*dim)(p_x,p_y,p_z)
cmplx = cellComplex_lib.new_cellComplex(p,dim)
^This doesn't work and I don't know why.
Problem 2. (Included here because it's glaring in Problem 1) I am returning an essentially anonymous pointer from my C
code! This just feels, well, dirty, and there must be a better way to return a custom data type and deal with it back in Python. For the record, I am extremely grateful for this stackoverflow answer where I learned such sorcery - but I'm not going to be able to sleep at night as long as it's in my code...