2011-03-01 7 views
3

私はCPythonの機能を持っている:関数ポインタをCPythonからPythonに戻すには、ctypesを使ってC関数を呼び出しますか?

void my_cfunc(int arg) 
{ 
    printf("Hello from C; arg=%d\n", arg); 
} 

PyObject *get_fptr(PyObject * /*self*/, PyObject * /*args*/) 
{ 
    return PyCObject_FromVoidPtr(my_cfunc, NULL); 
} 

はその後、Pythonで私が持っている:そして、

import mymodule 

ptr = mymodule.get_fptr() # will return a PyCObject wrapping the C function pointer 

以降:今

from ctypes import * 

SOMEFUNC_T = CFUNCTYPE(c_void, c_int) 
somefunc = SOMEFUNC_T(ptr) # <-- bad! 

、私のように返すようにget_fptr変更した場合:PyLong_FromSize_t (size_t(my_cfunc)) 'somefunc'が有効になります。

しかし私はsize_tに関数ポインタをキャストしたくありません。論理的なことがあろうが、あなたが、唯一(ctypesの経由)のPythonから呼び出すPythonの拡張からCの関数ポインタを返すようにしたいと思いますなぜ

すべての

答えて

1

ファーストを教えてください、私は理解していませんPython拡張機能を介してC関数を呼び出すことができます(何かが欠けていない限り)。

第2に、ctypesはPyCObjectをまったくサポートしていないようです。 CFUNCTYPE(None、c_int)を呼び出すと、CFUNCTYPEが整数を期待しているためPyCObject引数でC_voidをNoneに置き換えられません。PyCObjectの処理方法がわからないため、

代わりにmy_cfuncにPythonラッパーを書くのではなく、ctypesの手間をかけずにPythonから呼び出すのはなぜですか?たとえば:ctypesのはあなたのものであればボーナスとして

PyObject *call_fptr(PyObject *self, PyObject *args) 
{ 
    int arg; 
    if (!PyArg_ParseTuple(args, "i", &arg)) 
     return NULL; 

    my_cfunc(arg); 
    Py_RETURN_NONE; 
} 

は、my_funcへのPythonラッパーは、(PyCObjectとは違って)ctypesの外国機能をインスタンス化するために使用することができます!

from ctypes import * 
import foo 

SOMEFUNC_T = CFUNCTYPE(None, c_int) 
cfunc = SOMEFUNC_T(foo.call_fptr) 
cfunc(1) 

編集:あなたはCFUNCTYPEが必要であることを考えると、とにかくctypesのを使用して可変引数C関数をラップしますどのようにあなたの質問がより困難にC関数は引数の可変数を取る必要があることを指定 ...既知の引数の集合?

この場合の問題は、実際にはPythonタプルをCの可変引数リストに変換することになります。事実SWIGはこの問題にsection of its documentationを捧げています:他のほとんどのラッパー生成ツールはこの問題を避けるために賢明に選択しました

libffiの助けを借りて、移植可能な方法で可変引数リストを動的に構築することができます。

私の提案は、最終的に可変引数関数をSWIGでラップし、自分自身に苦痛を与えないことです。

+0

私は正確だったはずです。実際にはvoid my_cfunc(int arg)は次のようなものでなければなりません: "void my_cfunc(int n1、...)" .... 2つの解決策があります:(1)私がやっていること(2) Pythonでva_arg関数をラップする方法これは私がその関数ポインタを返し、後でそれを再びw/ctypeで呼び出す理由です。 –

+0

@Elias Bachaalany:答えの最後に私の更新を見てください。 – aknuds1

+0

いいえ、ctypesで簡単にva_arg関数をラップできます:) - 私の例のように、そのアドレスをctypesに取得するだけです。 - cfunc(1、2、3、4、5、6)を無制限に呼び出してください... - これはもっとうまくいきます:cfunc(* args) これは私がCの関数ポインタを取得してPythonに渡し、それをctypesに渡してから、va_arg関数を呼び出すことができます。 –

関連する問題