У меня есть следующая структура и объявление функции в C:
typedef int (*callback)(struct instance *);
typedef struct instance {
int x;
callback f;
} instance;
Каким будет правильный способ определить обратный вызов в Python с использованием ctypes?
Я пытаюсь объявить структуру в Python следующим образом:
class INSTANCE_STRUCT(ctypes.Structure):
_fields_ = [("x", c_int),
("f", c_void_p)]
Итак, в основном я использую c_void_p, чтобы объявить f как указатель void и хотел бы привести его к функции.
Я создаю структуру в исходном коде C в куче с помощью malloc, а затем в Python я обращаюсь к ней следующим образом:
instance = ctypes.cast(pointer_to_structure, ctypes.POINTER(INSTANCE_STRUCT))
print(instance.contents.x)
print(instance.contents.f)
Запуск скрипта дает мне следующий вывод:
Initializing struct x=[4] with function f() result=[8] // this happens in C and is correct
4 // value of instance.x
140027207110960 // address of instance.f (?)
Теперь, имея адрес instance.f(), я предполагаю, что мне нужно каким-то образом привести его к методу Python. Я пробовал это:
def CALLBACK_FUNC(self, structure):
pass
callback = ctypes.cast(instance.contents.f, ctypes.POINTER(CALLBACK_FUNC))
Но он просто выдает ошибку:
Traceback (most recent call last):
File "binding_test.py", line 19, in <module>
callback = ctypes.cast(instance.contents.f, ctypes.POINTER(callback_function))
TypeError: must be a ctypes type
Кто-нибудь знает, как можно разыменовать функцию instance.f() в Python, учитывая, что функция обратного вызова должна иметь сам объект INSTANCE_STRUCT в качестве параметра?






Указатели функций могут использовать CFUNCTYPE(retval,params...) для объявления указателей функций C. Приведенный ниже код является предположением, основанным на описании и минимальном коде:
тест.с
#if defined(_WIN32)
# define API __declspec(dllexport)
#else
# define API
#endif
#include <stdlib.h>
struct instance; // forward declaration...
typedef int (*callback)(struct instance *); // so callback can be defined...
typedef struct instance { // and structure declared.
int x;
callback f;
} instance;
int func(instance* p) { // Callback
return ++p->x;
}
API instance* get_instance(void) {
instance* p = malloc(sizeof(instance));
p->x = 5;
p->f = func;
return p;
}
API void free_instance(instance* p) {
free(p);
}
test.py
from ctypes import *
# Forward declaration...
class Instance(Structure):
pass
# so the callback parameter pointer can be declared...
CALLBACK = CFUNCTYPE(c_int,POINTER(Instance))
# and then the fields can be defined.
Instance._fields_ = (('x',c_int),
('f',CALLBACK))
dll = CDLL('./test')
dll.get_instance.argtypes = ()
dll.get_instance.restype = POINTER(Instance)
dll.free_instance.argtypes = POINTER(Instance),
dll.free_instance.restype = None
instance = dll.get_instance()
try:
print(instance.contents.x)
print(instance.contents.f(instance))
print(instance.contents.f(instance))
print(instance.contents.f(instance))
finally:
dll.free_instance(instance)
Выход:
5
6
7
8
Использованная литература:
Это именно то, что я искал, спасибо!