8

我有以下问题。我们必须将回调函数传递给 C 代码。如果函数是同一个模块中的Cython函数,情况就很简单了

在赛通:

def callme(int x):
    c_callme(x, <int (*)(int)>&callbackme) 

cdef int callbackme(int x):
    print <int> x
    return <int>x

在 C 中:

int c_callme(int x, int (*f)(int))
{
    printf("---%d\n",x);
    printf("--%d\n",f(x));
    return x;
}

问题如下:我们想以最 Pythonic 的方式概括此代码,以便它也可以接受 Python 函数作为回调参数(当然,需要一些额外的层),以及来自另一个模块的 C/Cython 函数。我想,对于来自单独模块的 C/Cython 函数,必须获取这些函数的地址(转换为 long int?),对于 Python 函数,需要某个包装器

4

2 回答 2

15

在此示例中,从 Python 包装器中提取Cubature 集成 C 库,将 Python 函数传递给具有由 给出的原型的 C 函数cfunction。您可以创建一个具有相同原型的函数,称为cfunction_cb(回调),并返回相同的类型,int在本例中):

cdef object f
ctypedef int (*cfunction) (double a, double b, double c, void *args)

cdef int cfunction_cb(double a, double b, double c, void *args):
    global f
    result_from_function = (<object>f)(a, b, c, *<tuple>args)
    for k in range(fdim):
        fval[k] = fval_buffer[k]
    return 0

调用 C 函数时,您可以使用 C 原型强制转换回调包装器:

def main(pythonf, double a, double b, double c, args): 
    global f
    f = pythonf
    c_function( <cfunction> cfunction_cb,
                double a,
                double b,
                double c,
                <void *> args )

在此示例中,还展示了如何通过 C 将参数传递给 Python 函数。

于 2013-08-29T12:17:05.737 回答
0

我认为最简单的方法是将 C 回调包装在

cdef class Callback(object):
    cdef int (*f)(int)        # I hope I got the syntax right...

    def __call__(int x):
        return self.f(x)

因此您可以将这种类型的对象以及任何其他可调用对象传递给必须调用回调的函数。

然而,如果你必须从 C 调用回调,那么你应该给它传递一个额外的参数,即 Python 对象的可选地址,可能转换为 `void*。

(请不要函数指针强制转换为long,否则您可能会得到未定义的行为。我不确定您是否可以安全地将函数指针强制转换为任何东西,甚至void*.)

于 2012-07-28T13:44:30.260 回答