如何通过ctypes将数组从C++函数返回到Python

29 投票
2 回答
27717 浏览
提问于 2025-04-17 15:57

我正在用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中访问数组的值吗?

2 个回答

28

你的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]

基本上有两个改动:

  1. 去掉和numpy相关的代码以及ctypes.cast的调用,因为我们不需要它们。

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

    默认情况下,外部函数被认为返回的是C语言的整型,所以我们需要把它改成想要的指针类型。

顺便说一下,从C代码返回一个new创建的数组到Python代码似乎不太合适。谁来释放这块内存呢?更好的做法是在Python代码中创建数组,然后传递给C代码。这样就很清楚,Python代码是这些数组的拥有者,负责创建和释放它们的内存空间。

24

function.cpp 返回的是一个整型数组,而 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()

撰写回答