ctype问题char **

时间:2009-08-28 14:16:56

标签: python ctypes

我试图弄清楚为什么在经过多次大量混乱后才能使用

obo.librar_version是一个c函数,它需要char **作为输入并执行strcpy 通过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'没有任何价值?有人有主意吗? THX

2 个答案:

答案 0 :(得分:1)

当您将s投射到c_char_p时,您会在t中存储新对象,而不是参考。因此,当您通过引用将t传递给您的函数时,s不会更新。

<强>更新

你确实是对的:

  

cast有两个参数,一个ctypes   是或可以转换为的对象   某种指针和一个ctypes   指针类型。它返回一个实例   第二个论点,哪个   引用相同的内存块   第一个论点。

为了获得对字符串缓冲区的引用,您需要使用以下内容进行转换:

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

我不知道为什么c_char_p没有创建引用,但是你去了。

答案 1 :(得分: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的值设置为指向以null结尾的字符数组的指针。这可能是真正的OBO_VERSION的工作原理。我已根据我上面提到的技术对此进行了测试,并按规定运行。