Как передать указатель функции на внешнюю программу в Cython - PullRequest
5 голосов
/ 10 января 2012

Я пытаюсь написать оболочку для программы на C, чтобы я мог вызывать ее из Python.Я использую Cython для этого.Функция C принимает функцию обратного вызова в качестве аргумента, но эта функция обратного вызова будет известна только во время выполнения программы python.Я искал, как это сделать, и кажется, что это не простое решение, но, кажется, работает следующее:

#python.py

libc = cdll.LoadLibrary("myfunc.so") #Callback function is defined in myfunc.so 
....
c_wrapper(libc.fun, ...)

.

#c_wrapper.pyx

cdef extern void mainfunction(void *F, ...) #The intial C function we are wrapping
ctypedef void (*myfuncptr) () 

def c_wrapper(f, ...) # our function pointer is passed to the wrapper as a Python object
    cdef myfuncptr thisfunc
    thisfunc = (<myfuncptr*><size_t>addressof(f))[0]
    mainfunction(thisfunc, ...)

Этот метод работает для функций C и FORTRAN(я предполагаю, что это будет работать для большинства скомпилированных языков) и функций Python (с использованием типов C), но это кажется немного неловким.Есть ли более простой способ сделать это в Cython?

Спасибо

РЕДАКТИРОВАТЬ: я не могу изменить библиотеку C я пытаюсь обернуть

1 Ответ

5 голосов
/ 10 января 2012

Полагаю, вы знаете о этом ?

Можно ли вызвать мой код Python из C?

Ответ: Да, без труда.Следуйте примеру в Demos / callback / в исходном коде Cython

Итак, зная, что вы можете загрузить свою основную функцию, давайте рассмотрим другой подход.Я написал пару глупых функций для проверки этого:

/* lib.c -> lib.so */
#include <stdio.h>

void fn1(void) {
        puts("Called function 1");
}

void fn2(void) {
        puts("Called function 2");
}

затем функция, которая принимает обратный вызов

/* main.c -> main.so */

typedef void (*callback)();

void mainfunction(void *F) {
        ((callback)F)();
}

, который можно передать непосредственно из Python:

>>> from ctypes import cdll
>>> lib = cdll.LoadLibrary('./lib.so')
>>> main = cdll.LoadLibrary('./main.so')
>>> main.mainfunction(lib.fn1)
Called function 1
>>> main.mainfunction(lib.fn2)
Called function 2

А теперь давайте обернем функцию Python:

>>> from ctypes import CFUNCTYPE
>>> def pyfn():
...     print "Called the Python function"
... 
>>> CWRAPPER = CFUNCTYPE(None)

>>> wrapped_py_func = CWRAPPER(pyfn)
>>> main.mainfunction(wrapped_py_func)
Called the Python function
...