是否可以使用Cython将指向编译时未知函数的C函数指针传递给C函数



我正试图从Python中调用一个以函数指针为参数的C函数。我需要在运行时动态确定该函数。使用ctypes,这非常简单。

C代码可能是这样的:

// my_c_funcs.h
double mul(double, double);
double add(double, double);
double do_something(double (*)(double, double), double, double);
// my_c_funcs.h
int mul(int a, int b) {
return a*b;
}
int add(int a, int b) {
return a + b;
}
int do_something(int (*f)(int, int), int a, int b) {
return f(a, b);
}

在将该代码编译成名为"的共享库之后;libMyCFuncs.so";,我可以使用ctypes:在Python中传递在运行时确定的函数

# foo.py
import ctypes
lib = ctypes.cdll.LoadLibrary("./libMyCfuncs.so")
def foo(func_name, a, b):
func = getattr(lib, func_name)
return lib.do_something(func, a, b)

我知道我应该定义返回类型,但为了简洁起见,我省略了它,只使用了ints。

上面的代码给出了预期的结果,例如调用foo.foo('add', 2, 4)会产生6。然而,我更喜欢使用Cython,因为我大量使用二维或更高维的数组,并且在Cython中传递数组更容易IMHO。假设Cython代码在";foo.pyx":

# foo.pyx
cdef extern from "my_c_funcs.h":
int mul(int, int)
int add(int, int)
int do_something(int (*)(int, int), int, int)
def foo(func_name, int a, int b):
# ???

调用getattr甚至eval显然不起作用。那么我怎么能在Cython中意识到这一点呢?

您必须从cython提供一个可以在共享对象中调用的包装器。Cython基本上有三个";模式";

  1. def:普通python函数
  2. cpdef:python可调用函数,可能包含c/cpp内部变量
  3. cdef:纯c/cpp函数

作为代码的一个例子,一个简单的绑定是


cdef extern from "c_funcs.h":
double mul(double, double)
double add (double, double)
double do_something(double(*)(double, double), double, double)
cdef extern from "c_funcs.c":
pass
# this is callable from python
cpdef double py_do_something_mul(str name, double x,  double y):
return do_something(mul, x, y)

如果您想要像动态调度这样的东西,那么您也必须对此提供一些包装。它不适用于默认的python dicts,但有序或非有序的map可以用于此。

最新更新