ctype问题 char**

1 投票
2 回答
2237 浏览
提问于 2025-04-15 13:56

我在琢磨为什么这个代码能正常工作,经过了很多次的尝试。

obo.librar_version是一个C语言的函数,它需要一个字符指针的指针(char **)作为输入,并且会把内容复制到传入的字符中。

from ctypes import *
_OBO_C_DLL = 'obo.dll'
STRING = c_char_p

OBO_VERSION = _stdcall_libraries[_OBO_C_DLL].OBO_VERSION
OBO_VERSION.restype = c_int
OBO_VERSION.argtypes = [POINTER(STRING)]

def library_version():
    s = create_string_buffer('\000' * 32)
    t = cast(s, c_char_p)
    res = obo.library_version(byref(t))
    if res != 0:
        raise Error("OBO error %r" % res)
    return t.value, s.raw, s.value

library_version()

上面的代码返回了

('OBO Version 1.0.1', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', '')

我不明白的是,为什么's'没有任何值?有没有人能给点建议?谢谢!

2 个回答

0

因为library_version需要一个char**类型的参数,所以他们不希望你像使用create_string_buffer那样去分配字符。相反,他们只是想让你传入一个指向指针的引用,这样他们就可以返回一个地址,告诉你在哪里可以找到版本字符串。

所以你需要做的就是分配一个指针,然后把这个指针的引用传进去。

下面的代码应该可以正常工作,虽然我没有obo.dll(也不知道有什么合适的替代品)来测试它。

from ctypes import *
_OBO_C_DLL = 'obo.dll'
STRING = c_char_p

_stdcall_libraries = dict()
_stdcall_libraries[_OBO_C_DLL] = WinDLL(_OBO_C_DLL)
OBO_VERSION = _stdcall_libraries[_OBO_C_DLL].OBO_VERSION
OBO_VERSION.restype = c_int
OBO_VERSION.argtypes = [POINTER(STRING)]

def library_version():
    s_res = c_char_p()
    res = OBO_VERSION(byref(s_res))
    if res != 0:
        raise Error("OBO error %r" % res)
    return s_res.value

library_version()

[编辑]

我更进一步,写了自己的DLL,里面实现了一个可能的OBO_VERSION,不需要分配字符缓冲区,也不会出现内存泄漏的问题。

int OBO_VERSION(char **pp_version)
{
    static char result[] = "Version 2.0";

    *pp_version = result;
    return 0; // success
}

正如你所看到的,OBO_VERSION只是将*pp_version的值设置为一个指向以空字符结尾的字符数组的指针。这可能就是实际的OBO_VERSION的工作方式。我已经将这个方法与我之前建议的技术进行了测试,结果是可以正常工作的。

1

当你把 s 转换成 c_char_p 时,其实是在 t 里存了一个新的对象,而不是一个引用。所以,当你把 t 传给你的函数时,s 并不会被更新。

更新:

你说得没错:

转换(cast)需要两个参数,一个是 ctypes 对象,它可以是某种指针,另一个是 ctypes 指针类型。这个操作会返回第二个参数的一个实例,它会指向和第一个参数相同的内存块。

如果你想要获取字符串缓冲区的引用,你需要用下面的方式进行转换:

t = cast(s, POINTER(c_char*33))

我也不知道为什么 c_char_p 不会创建一个引用,而这个会,但就是这样。

撰写回答