I have the following struct and function declaration in C:
typedef int (*callback)(struct instance *);
typedef struct instance {
int x;
callback f;
} instance;
What would be the proper way to define the callback in Python using ctypes?
I'm trying to do declare the struct in Python the following way:
class INSTANCE_STRUCT(ctypes.Structure):
_fields_ = [("x", c_int),
("f", c_void_p)]
So basically I'm using c_void_p
to declare f
as a void pointer and would like to cast it to a function.
I'm creating the structure in the C source on the heap with malloc, and then in Python I'm accessing it as follows:
instance = ctypes.cast(pointer_to_structure, ctypes.POINTER(INSTANCE_STRUCT))
print(instance.contents.x)
print(instance.contents.f)
Running the script gives me the following output:
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 (?)
Now having the address of instance.f()
I assume I'd need to cast it somehow to a python method. I tried this:
def CALLBACK_FUNC(self, structure):
pass
callback = ctypes.cast(instance.contents.f, ctypes.POINTER(CALLBACK_FUNC))
But it just throws the error:
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
Does anybody know what would be the way to dereference the instance.f() function in Python, considering that the callback function should have the INSTANCE_STRUCT object itself as a parameter?
Function pointers can use CFUNCTYPE(retval,params...)
to declare C function pointers. The code below is a guess based on the description and minimal code:
test.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)
Output:
5
6
7
8
References:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.