I have a C interface that looks like this (simplified):
extern bool Operation(void ** ppData); extern float GetFieldValue(void* pData); extern void Cleanup(p);
which is used as follows:
void * p = NULL; float theAnswer = 0.0f; if (Operation(&p)) { theAnswer = GetFieldValue(p); Cleanup(p); }
You’ll note that Operation() allocates the buffer p, that GetFieldValue queries p, and that Cleanup frees p. I don’t have any control over the C interface — that code is widely used elsewhere.
I’d like to call this code from Python via SWIG, but I was unable to find any good examples of how to pass a pointer to a pointer — and retrieve its value.
I think the correct way to do this is by use of typemaps, so I defined an interface that would automatically dereference p for me on the C side:
%typemap(in) void** { $1 = (void**)&($input); }
However, I was unable to get the following python code to work:
import test p = None theAnswer = 0.0f if test.Operation(p): theAnswer = test.GetFieldValue(p) test.Cleanup(p)
After calling test.Operation(), p always kept its initial value of None.
Any help with figuring out the correct way to do this in SWIG would be much appreciated. Otherwise, I’m likely to just write a C++ wrapper around the C code that stops Python from having to deal with the pointer. And then wrap that wrapper with SWIG. Somebody stop me!
Edit:
Thanks to Jorenko, I now have the following SWIG interface:
% module Test %typemap (in,numinputs=0) void** (void *temp) { $1 = &temp; } %typemap (argout) void** { PyObject *obj = PyCObject_FromVoidPtr(*$1, Cleanup); $result = PyTuple_Pack(2, $result, obj); } %{ extern bool Operation(void ** ppData); extern float GetFieldValue(void *p); extern void Cleanup(void *p); %} %inline %{ float gfv(void *p){ return GetFieldValue(p);} %} %typemap (in) void* { if (PyCObject_Check($input)) { $1 = PyCObject_AsVoidPtr($input); } }
The python code that uses this SWIG interface is as follows:
import test success, p = test.Operation() if success: f = test.GetFieldValue(p) # This doesn't work f = test.gvp(p) # This works! test.Cleanup(p)
Oddly, in the python code, test.GetFieldValue(p) returns gibberish, but test.gfv(p) returns the correct value. I’ve inserting debugging code into the typemap for void*, and both have the same value of p! The call Any ideas about that?
Update: I’ve decided to use ctypes. MUCH easier.
I agree with theller, you should use ctypes instead. It’s always easier than thinking about typemaps.
But, if you’re dead set on using swig, what you need to do is make a typemap for
void**that RETURNS the newly allocatedvoid*:Then your python looks like:
Edit:
I’d expect swig to handle a simple by-value
void*arg gracefully on its own, but just in case, here’s swig code to wrap thevoid*for GetFieldValue() and Cleanup():