如何在Cython中将函数指针传递给外部程序

7 投票
1 回答
4726 浏览
提问于 2025-04-17 09:55

我正在尝试为一个C程序写一个包装器,这样我就可以从Python中调用它。我使用Cython来实现这个目标。这个C函数需要一个回调函数作为参数,但这个回调函数只有在Python程序运行时才能知道。我一直在寻找如何做到这一点,似乎没有简单的解决方案,但以下方法似乎有效:

#python.py

libc = cdll.LoadLibrary("myfunc.so") #Callback function is defined in myfunc.so 
....
c_wrapper(libc.fun, ...)

.

#c_wrapper.pyx

cdef extern void mainfunction(void *F, ...) #The intial C function we are wrapping
ctypedef void (*myfuncptr) () 

def c_wrapper(f, ...) # our function pointer is passed to the wrapper as a Python object
    cdef myfuncptr thisfunc
    thisfunc = (<myfuncptr*><size_t>addressof(f))[0]
    mainfunction(thisfunc, ...)

这个方法适用于C和FORTRAN函数(我假设它对大多数编译语言也有效),以及Python函数(使用C类型),但看起来有点笨拙。有没有更简单的方法可以在Cython中做到这一点?

谢谢

编辑:我无法更改我尝试包装的C库

1 个回答

8

我想你应该知道这个吧?

可以从C语言调用我的Python代码吗?

答案是:可以,非常简单。只需参考Cython源代码中的Demos/callback/示例。

所以,既然你知道可以下载你的主函数,我们来换个方式。我写了一些简单的函数来测试这个:

/* lib.c -> lib.so */
#include <stdio.h>

void fn1(void) {
        puts("Called function 1");
}

void fn2(void) {
        puts("Called function 2");
}

然后是接受回调的函数:

/* main.c -> main.so */

typedef void (*callback)();

void mainfunction(void *F) {
        ((callback)F)();
}

这个函数可以直接从Python传递过来:

>>> from ctypes import cdll
>>> lib = cdll.LoadLibrary('./lib.so')
>>> main = cdll.LoadLibrary('./main.so')
>>> main.mainfunction(lib.fn1)
Called function 1
>>> main.mainfunction(lib.fn2)
Called function 2

现在,让我们来封装一个Python函数:

>>> from ctypes import CFUNCTYPE
>>> def pyfn():
...     print "Called the Python function"
... 
>>> CWRAPPER = CFUNCTYPE(None)

>>> wrapped_py_func = CWRAPPER(pyfn)
>>> main.mainfunction(wrapped_py_func)
Called the Python function

撰写回答