我有CPython功能:
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);
}
然后,在Python中我有:
import mymodule
ptr = mymodule.get_fptr() # will return a PyCObject wrapping the C function pointer
然后:
from ctypes import *
SOMEFUNC_T = CFUNCTYPE(c_void, c_int)
somefunc = SOMEFUNC_T(ptr) # <-- bad!
现在,如果我将get_fptr更改为:PyLong_FromSize_t(size_t(my_cfunc)),那么'somefunc'将有效。
但我不想将函数指针强制转换为size_t。
请告知
答案 0 :(得分:1)
首先,我不明白你为什么要从Python扩展中返回一个C函数指针只是为了从Python调用它(通过ctypes),而逻辑上就是通过c函数来调用C函数Python扩展(除非我遗漏了什么)。
其次,它看起来并不像ctypes支持PyCObject。你用CFCObject参数调用CFUNCTYPE(None,c_int)[我用无替换c_void]失败了,因为CFUNCTYPE需要一个整数,并且不知道如何处理PyCObject。
为什么不把一个Python包装器改为my_cfunc,你可以从Python调用它而没有ctypes的麻烦?例如:
PyObject *call_fptr(PyObject *self, PyObject *args)
{
int arg;
if (!PyArg_ParseTuple(args, "i", &arg))
return NULL;
my_cfunc(arg);
Py_RETURN_NONE;
}
作为奖励,如果ctypes是你的东西,my_func的Python包装器可用于实例化ctypes外部函数(与PyCObject不同)!
from ctypes import *
import foo
SOMEFUNC_T = CFUNCTYPE(None, c_int)
cfunc = SOMEFUNC_T(foo.call_fptr)
cfunc(1)
修改强> 指定C函数应该使用可变数量的参数会使你的问题变得更加困难......无论如何,你如何用ctypes包装你的变量参数C函数,考虑到CFUNCTYPE需要一组已知的参数?
在这种情况下的问题实际上归结为将Python元组转换为C中的变量参数列表,这显然是微不足道的。事实上,SWIG已经为此问题专门设置section of its documentation,例如:大多数其他包装器生成工具都明智地选择了以避免此问题。
但它确实提供了建议,即可以在libffi的帮助下以可移植的方式动态构造变量参数列表。
我的建议最终是用SWIG包装你的变量参数函数,并为自己省去痛苦。