Reputation: 1200
I have CPython function:
void my_cfunc(int arg)
{
printf("Hello from C; arg=%d\n", arg);
}
PyObject *get_fptr(PyObject * /*self*/, PyObject * /*args*/)
{
return PyCObject_FromVoidPtr(my_cfunc, NULL);
}
Then later, in Python I have:
import mymodule
ptr = mymodule.get_fptr() # will return a PyCObject wrapping the C function pointer
Then later:
from ctypes import *
SOMEFUNC_T = CFUNCTYPE(c_void, c_int)
somefunc = SOMEFUNC_T(ptr) # <-- bad!
Now, if I change get_fptr to return as: PyLong_FromSize_t(size_t(my_cfunc)) then 'somefunc' will be valid.
But I don't want to cast a function pointer to a size_t.
Please advise
Upvotes: 3
Views: 1368
Reputation: 67997
First of all, I don't understand why you'd want to return a C function pointer from a Python extension only to call it from Python (via ctypes), while the logical thing would be to call the C function via the Python extension (unless I'm missing something).
Second, it does not look like ctypes supports PyCObject at all. Your call to CFUNCTYPE(None, c_int) [I replaced c_void with None] with a PyCObject argument fails because CFUNCTYPE expects an integer, and does not know what to do with a PyCObject.
Why not write a Python wrapper to my_cfunc instead, which you'll call from Python without the ctypes hassle? For example:
PyObject *call_fptr(PyObject *self, PyObject *args)
{
int arg;
if (!PyArg_ParseTuple(args, "i", &arg))
return NULL;
my_cfunc(arg);
Py_RETURN_NONE;
}
As a bonus, if ctypes is your thing, the Python wrapper to my_func can be used to instantiate a ctypes foreign function (unlike the PyCObject)!
from ctypes import *
import foo
SOMEFUNC_T = CFUNCTYPE(None, c_int)
cfunc = SOMEFUNC_T(foo.call_fptr)
cfunc(1)
Edit: Specifying that the C function should take a variable number of arguments makes your question more difficult... How would you wrap your variable argument C function with ctypes anyway, considering that CFUNCTYPE requires a known set of arguments?
The problem in this case really boils down to converting a Python tuple to a variable argument list in C, which is apparently anything but trivial. In fact SWIG has dedicated a section of its documentation to this problem, saying for instance this: Most other wrapper generation tools have wisely chosen to avoid this issue.
It does give the advise, though, that one can dynamically construct variable argument lists in a portable manner with the help of libffi.
My suggestion, ultimately, is to wrap your variable arguments function with SWIG and save yourself the pain.
Upvotes: 1