如何将函数指针从CPython返回到Python然后使用ctypes调用C函数?

时间:2011-03-01 18:33:12

标签: python function pointers casting ctypes

我有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。

请告知

1 个答案:

答案 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包装你的变量参数函数,并为自己省去痛苦。