简体   繁体   English

在 Python/ctypes 中的结构内取消引用 C function 指针

[英]Dereferencing C function pointer inside a struct in Python/ctypes

I have the following struct and function declaration in C:我在 C 中有以下结构和 function 声明:

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?使用 ctypes 在 Python 中定义回调的正确方法是什么?

I'm trying to do declare the struct in Python the following way:我正在尝试通过以下方式在 Python 中声明结构:

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.所以基本上我使用c_void_pf声明为 void 指针,并希望将其转换为 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:我正在使用 malloc 在堆上的 C 源中创建结构,然后在 Python 中访问它,如下所示:

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:运行脚本会给我以下 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.现在有了instance.f()的地址,我假设我需要以某种方式将其转换为 python 方法。 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? 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. Function 指针可以使用CFUNCTYPE(retval,params...)来声明 C function 指针。 The code below is a guess based on the description and minimal code:下面的代码是基于描述和最小代码的猜测:

test.c测试.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测试.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: Output:

5
6
7
8

References:参考:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM