1

我正在使用 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) 

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

4

1 回答 1

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
于 2013-04-03T14:00:10.917 回答