2011-03-01 42 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。

請告知

回答

1

首先,我不明白爲什麼你會想從一個Python擴展返回一個C函數指針只把它從Python中調用(通過ctypes的),而順理成章的事情會是通過Python擴展調用C函數(除非我錯過了某些東西)。

其次,看起來ctypes完全不支持PyCObject。你調用CFUNCTYPE(None,c_int)[我用None替換c_void]帶有PyCObject參數會失敗,因爲CFUNCTYPE需要一個整數,並且不知道如何處理PyCObject。

爲什麼不寫一個Python包裝到my_cfunc來代替,你會從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; 
} 

作爲獎勵,如果ctypes的是你的事,Python的包裝,以my_func,並將可用於實例化一個ctypes外國功能(不同於PyCObject)!

from ctypes import * 
import foo 

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

編輯: 指定的C函數應採取可變數量的參數,使您的問題更加困難......你會怎麼纏上你的ctypes可變參數的C函數,無論如何,考慮到CFUNCTYPE要求已知的一組論據?

在這種情況下,問題真的歸結爲將Python元組轉換爲C中的變量參數列表,這顯然不過是微不足道的。事實上,SWIG專門爲此問題專門設計了一個section of its documentation,比如說:大多數其他包裝生成工具已經明智地選擇以避免此問題

儘管如此,人們可以藉助libffi以便攜方式動態構建可變參數列表。

我的建議最終是用SWIG來包裝你的可變參數函數,並節省自己的痛苦。

+0

好吧,我應該是精確的。其實void my_cfunc(int arg)應該是這樣的:「void my_cfunc(int n1,...)」.... 所以,我有兩個解決方案:(1)我在做什麼(2)我沒有想法如何在Python中包裝va_arg函數。這就是爲什麼我要求返回它的函數指針,然後再次調用它的w/ctypes –

+0

@Elias Bachaalany:在答案的最後看到我的更新。 – aknuds1

+0

不,用ctypes你可以很容易地包裝一個va_arg函數:) - 只需將它的地址給ctypes(就像我的示例所示)。 (1,2,3,4,5,6)... - 甚至更好,你可以把它叫做:cfunc(* args) 這就是爲什麼我想要獲取C函數指針並將其提供給Python,然後將其提供給ctypes,然後我可以調用va_arg函數。 –

相關問題