使用ctypes python包装C函数返回未知大小的数组

Posted

技术标签:

【中文标题】使用ctypes python包装C函数返回未知大小的数组【英文标题】:Wrap C Function returning array of unknown size using ctypes python 【发布时间】:2017-05-21 00:32:45 【问题描述】:

我正在尝试使用 ctypes 包装一个 C 函数,它返回一个未知大小的字符数组。函数是from the gdal c api,但我的问题并不特定于该函数。

我想知道是否有一种通用方法可以解构返回未知大小的 char** 数组对象的函数的输出。在 ctypes 中,这将是 POINTER(c_char_p * X),其中 X 未知。

使用来自answer to a similar question 的提示,我能够得到以下工作:

# Define the function wrapper.
f = ctypes.CDLL('libgdal.so.20').GDALGetMetadata
MAX_OUTPUT_LENGTH = 10
f.restype = ctypes.POINTER(ctypes.c_char_p * MAX_OUTPUT_LENGTH)
f.argtypes = [ctypes.c_void_p, ctypes.c_char_p]

# Example call (the second argument can be null).
result = []
counter = 0
output = f(ptr, None).contents[counter]
while output:
    result.append(output)
    counter += 1
    output = f(ptr, None).contents[counter]

其中output 是结果数组,ptr 是指向打开的 GDALRaster 的 ctypes 指针。对此的限制是我必须在调用函数之前构造一个固定长度的数组。我可以猜测实际情况下的最大长度是多少,然后简单地使用它。但这是任意的,我想知道是否有一种方法可以在不指定数组长度的情况下获取数组指针。换句话说:

有没有办法做类似上面例子的事情,但不指定任意最大长度?

【问题讨论】:

【参考方案1】:

事实证明,如果函数输出是以空字符结尾的字符数组,您可以简单地将指针传递给c_char_p 对象无需指定长度 作为 restype 参数。然后循环遍历结果,直到找到 null 元素,这表示数组的结尾。

所以以下内容非常适合我的用例:

# Define the function wrapper, the restype can simply be a
# pointer to c_char_p (without length!).
f = ctypes.CDLL('libgdal.so.20').GDALGetMetadata
f.restype = ctypes.POINTER(ctypes.c_char_p)
f.argtypes = [ctypes.c_void_p, ctypes.c_char_p]

# Prepare python result array.
result = []

# Call C function.
output = f(ptr, None)

# Ensure that output is not a null pointer.
if output:
    # Get first item from array.
    counter = 0
    item = output[counter]
    # Get more items, until the array accessor returns null.
    # The function output (at least in my use case) is a null
    # terminated char array.
    while item:
        result.append(item)
        counter += 1
        item = output[counter]

【讨论】:

以上是关于使用ctypes python包装C函数返回未知大小的数组的主要内容,如果未能解决你的问题,请参考以下文章

将 FILE * 从 Python / ctypes 传递给函数

从 Python (ctypes) 指向 C 以保存函数输出的指针

难以从 Ctypes 返回浮点数

使用Python中的C:如何创建ctypes包装器

通过 ctypes 从 Python 调用的 C 函数返回不正确的值

使用 ctypes 包装 DLL 函数