如何使用 ctypes 将数组从 C++ 函数返回到 Python

Posted

技术标签:

【中文标题】如何使用 ctypes 将数组从 C++ 函数返回到 Python【英文标题】:How to return array from C++ function to Python using ctypes 【发布时间】:2013-01-30 23:53:56 【问题描述】:

我正在使用 ctypes 在 Python 中实现一个 C++ 函数。 C++ 函数应该返回一个指向数组的指针。不幸的是,我还没有弄清楚如何在 Python 中访问数组。我尝试了 numpy.frombuffer,但没有成功。它只是返回了一个任意数字的数组。显然我没有正确使用它。这是一个大小为 10 的数组的简单示例:

function.cpp的内容:

extern "C" int* function()
int* information = new int[10];
for(int k=0;k<10;k++)
    information[k] = k;

return information;

wrapper.py 的内容:

import ctypes
import numpy as np

output = ctypes.CDLL('./library.so').function()

ArrayType = ctypes.c_double*10
array_pointer = ctypes.cast(output, ctypes.POINTER(ArrayType))
print np.frombuffer(array_pointer.contents)

要编译我正在使用的 C++ 文件:

g++ -c -fPIC function.cpp -o function.o
g++ -shared -Wl,-soname,library.so -o library.so function.o

您对我在 Python 中访问数组值有什么建议吗?

【问题讨论】:

当然我忘了导入一些特定的 ctypes 函数,比如 c_double 和 POINTER。我只是忘了在这里添加它们。 【参考方案1】:

你的python代码在一些小的修改后就可以工作了:

import ctypes

f = ctypes.CDLL('./library.so').function
f.restype = ctypes.POINTER(ctypes.c_int * 10)
print [i for i in f().contents] # output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

基本上有两个变化:

    删除与 numpy 相关的代码和 ctypes.cast 调用,因为我们不需要它们。

    将返回类型指定为ctypes.POINTER(ctypes.c_int * 10)

    默认情况下,外部函数假定返回 C int 类型,因此我们需要将其更改为所需的指针类型。

顺便说一句,将 newed 数组从 C 代码返回到 Python 代码似乎不合适。谁以及何时释放内存?最好在 Python 代码中创建数组并将它们传递给 C 代码。这样一来,很明显 Python 代码拥有数组并负责创建和回收它们的空间。

【讨论】:

你能指出我们如何在python中创建这样一个数组并将它的指针传递给C吗? @Shahensha 我对 int/float 数组所做的是使用 numpy 数组和嵌入式 ctypes 接口 (data_as) 这里有点死灵术......完成后你将如何删除内存?【参考方案2】:

function.cpp 返回一个 int 数组,而 wrapper.py 尝试将它们解释为双精度数。将ArrayType 更改为ctypes.c_int * 10,它应该可以工作。


自己使用np.ctypeslib 而不是frombuffer 可能更容易。这应该看起来像

import ctypes
from numpy.ctypeslib import ndpointer

lib = ctypes.CDLL('./library.so')
lib.function.restype = ndpointer(dtype=ctypes.c_int, shape=(10,))

res = lib.function()

【讨论】:

我还导入了 c_int 并替换了 c_double 但是python现在打印了一个只有 5 个元素的数组,并且值仍然是错误的。这很奇怪。 太好了,非常感谢!现在可以了。 Python 只是给了我警告“[...] RuntimeWarning: Invalid PEP 3118 format string: '

this discussion 这不是问题。

这里有点死灵术......完成后你将如何删除内存? @XapaJlaMnu 你的库应该有一个相应的extern C 函数来调用以释放内存,如果它是用new 分配的,则它在内部使用C++ delete。 ctypes 使用 C 接口,由于 C 没有delete,所以 ctypes 也没有。 正如另一个答案中所建议的那样,如果可能的话,通常最好用 numpy 分配内存并将其传递给 C 函数进行填充。

以上是关于如何使用 ctypes 将数组从 C++ 函数返回到 Python的主要内容,如果未能解决你的问题,请参考以下文章

使用 ctypes 返回值

难以从 Ctypes 返回浮点数

Python ctypes:如何调用应该返回字符串数组的函数?

使用 ctypes 将数组从 Python 传递到 C++,无法完全处理它

使用 ctypes 将 (uint8) NumPy 数组从 python 传递到 c++

使用 ctypes 从 python 到 c++ 的数据传输