为什么双“ctypes.POINTER”对象适用于“char***”,而三重“ctypes.POINTER”对象更有意义?

问题描述 投票:0回答:1

我有一个库

my_lib
,其中包含一个 C 函数,该函数采用
char***
参数,即指向由函数分配的
char*
数组的指针。这是此类函数的最小可重现示例:

void getArrayOfStrings(char*** paramPtr)
{
    (*paramPtr) = (char**) malloc(3*sizeof(char*));
    
    (*paramPtr)[0] = (char*) malloc(strlen("Foo")+1);
    strcpy((*paramPtr)[0], "Foo");
    
    (*paramPtr)[1] = (char*) malloc(strlen("Bar")+1);
    strcpy((*paramPtr)[1], "Bar");
    
    (*paramPtr)[2] = 0;
}

它将最后一个数组元素设置为 0,以便调用者可以识别它(而不是提供大小作为第二个参数)。请注意,提供了一个单独的函数来释放内存。

我运行

ctypesgen
来生成与此函数的 Python 绑定。它生成此代码:

getArrayOfStrings = _lib.get("getArrayOfStrings", "cdecl")
getArrayOfStrings.argtypes = [POINTER(POINTER(POINTER(c_char)))]
getArrayOfStrings.restype = None

可以从下面的 Python 脚本调用生成的绑定:

import my_lib

import ctypes
names = ctypes.POINTER(ctypes.POINTER(ctypes.c_char))()

my_lib.getArrayOfStrings(names)

if names:
    for name in names:
        name_str = my_lib.String(name)
        if name_str:
            print("Got name: " + str(name_str))
        else:
            break

它工作得很好并打印“Foo 酒吧 ”

我只是想知道为什么使用

ctypes.POINTER(ctypes.POINTER(ctypes.c_char))
,我理解为“指向字符的指针”,所以
char**
可以工作。为什么我不应该使用
ctypes.POINTER(ctypes.POINTER(ctypes.POINTER(ctypes.c_char)))

我用

ctypes.POINTER(ctypes.POINTER(ctypes.POINTER(ctypes.c_char)))
进行了测试,相同的代码会产生错误:

my_lib.getArrayOfStrings(names)
OSError: exception: access violation writing 0x0000000000000000
python c pointers ctypes
1个回答
0
投票

因为

ctypes
知道该函数由于定义了
char***
而采用
.argtypes
,所以传递
char**
意味着
ctypes.byref
(获取地址),从而将
names
作为
char***
传递。 这是一个使用显式
byref
并将 C 代码用作 DLL 的工作示例:

import ctypes as ct

dll = ct.CDLL('./test')
getArrayOfStrings = dll.getArrayOfStrings
getArrayOfStrings.argtypes = ct.POINTER(ct.POINTER(ct.POINTER(ct.c_char))),
getArrayOfStrings.restype = None

names = ct.POINTER(ct.POINTER(ct.c_char))()
dll.getArrayOfStrings(ct.byref(names))
#dll.getArrayOfStrings(names)  # also works but byref implied here.
i = 0
while names[i]:
    print(ct.string_at(names[i]))
    i += 1

输出:

b'Foo'
b'Bar'
© www.soinside.com 2019 - 2024. All rights reserved.