使用ctypes编写回调函数,该函数将传入指针指向要用作输出参数的指针参数

时间:2013-04-03 11:53:39

标签: python callback ctypes

我正在使用ctypes将python代码与传统C DLL接口。 DLL期望我给它一个函数指针,用作回调函数,然后从DLL中调用它。

该回调的C声明看起来像

char foo(char **buf)

从语义上讲,DLL期望我将buf指向由回调管理的字符串缓冲区,如果一切正常,则返回0。在C中,这将是一个静态char []变量mybuf,我会将该静态buf的地址传回给代码,如

*buf = &mybuf[0] ;
return (char)0 ;

mybuf中的字符串需要像往常一样在C中终止。我能够将函数指针传递给DLL,现在是一个python(成员)函数

def pyfoo(self, char_ptr_ptr) 

被召唤。

定义pyfoo的类也初始化(在 init 中)一个字段

self.response=create_string_buffer("The Response String")

如何将此字符串实际存储在内存中的地址传递给DLL? 由于ctypes有时创建副本而不是通过地址返回真正的引用,我尝试了类似

的内容
cpointer = c_int.from_address(char_ptr_ptr[0])
cpointer.value = addressof(self.response)
return c_char(0)

它不起作用。 我尝试了其他方法解除引用传递的指针指针并在那里存储一个内存地址(例如直接存储(我认为是字符串的地址)到char-ptr_ptr [0]),但回调的调用者从不这样做我期待它做什么。

如果有人解决了在python中创建空终止字符串的问题,并通过指向C中实现的DLL的**指针传递该字符串的地址,我将非常感谢他/她如何解决了这个问题。谢谢!

(编辑)或者我的问题更简单了吗?是

c_char(0) 

实际上将单个字节作为返回值推送到堆栈?如果没有,那么实现一个返回单个字节的回调的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

我使用以下函数原型:

CFUNCTYPE(c_byte, POINTER(POINTER(c_char)))

并像这样写pyfoo

    def pyfoo(self, char_ptr_ptr):
        char_ptr_ptr[0] = self.response
        return 0

例如:

>>> import os
>>> from ctypes import *

>>> open('tmp.c', 'w').write(r'''
... #include <stdio.h>
... typedef char (*callback_t)(char **buf);
... int test(callback_t foo)
... {
...     char res, *buf;
...     res = foo(&buf);
...     printf("res: %d\n", res);
...     printf("buf: %s\n", buf);
...     return 0;
... }
... ''')
>>> _ = os.system('gcc -shared -fPIC -o tmp.so tmp.c')
>>> lib = CDLL('./tmp.so')

>>> class Test(object):
...   def __init__(self):
...     self.response = create_string_buffer("The Response String")
...     self.callback = CFUNCTYPE(c_byte, POINTER(POINTER(c_char)))(self.pyfoo)
...   def pyfoo(self, char_ptr_ptr):
...     char_ptr_ptr[0] = self.response
...     return 0
... 

>>> t = Test()
>>> _ = lib.test(t.callback)
res: 0
buf: The Response String