8

次の質問があります。コールバック関数を C コードに渡す必要があります。関数が同じモジュール内の Cython 関数である場合、状況は非常に単純です。

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では、(callback)と呼ばれる同じプロトタイプを持ち、同じ型を返す関数を作成できます)。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 に答える