2012-07-28 205 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