2012-07-28 203 views
5

我有以下问题。 我们必须将回调函数传递给C代码。如果该功能是相同的模块中的用Cython功能,情况是相当简单的Python/Cython/C和回调函数,使用Cython从C调用Python函数

在用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; 
} 

的问题如下:我们要以最Python的方式概括这些代码,以便它也可以接受python函数作为回调参数(当然,需要一些额外的图层)以及另一个模块的C/Cython函数。我想,从一个单独的模块的C/Cython函数必须得到这些函数的地址(转换为长整型?)和Python函数需要一定的包装

+0

请阅读代码格式... – ThiefMaster 2012-07-28 11:16:09

回答

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*。)

+0

我也想在这个方向的常见问题。但是代码根本不能编译:(你能详细说明为什么我们不需要强制使用函数指针吗? – 2012-07-28 19:01:50

+0

@IvanOseledets:函数指针值不能保证适合'long',反之亦然。可能在一台机器上工作,但是在另一台机器上却失败了,这段代码没有编译,可能是由于语法错误,我没有安装Cython, – 2012-07-29 12:45:56

9

在这个例子中,extracted from a Python wrapperCubature integration C library,Python函数被传递给具有由cfunction给出的原型的C函数。您可以创建具有相同的原型的功能,称为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) 

在这个例子中它也展示了如何参数传递给你的Python功能,通过C.

+1

这应该被接受为答案,它工作正常。实例使实例保持活跃状态​​。 – dashesy 2014-08-07 17:02:08