我有一个 C++ 函数,我希望你在 Python 2.7.12 中调用它,如下所示:
extern "C" {
double* myfunction(double* &y, double* &z, int &n_y, int &n_z, int a, int b)
{
vector<double> _x;
vector<double> _y;
vector<double> _z;
// Call some external C++ function
cpp_function(_x, _y, _z, a, b);
// Convert vectors back to arrays
double* x = &_x[0]; // or x = _x.data();
y = &_y[0];
z = &_z[0];
n_y = static_cast<int>(_y.size());
n_z = static_cast<int>(_z.size());
return x;
}
}
基本上这个函数接受两个整数
a,b
作为输入(加上为了清晰起见我省略了一些其他数据),并在将结果放入两个数组y, z
并将它们各自的大小放入n_y, n_z
之前进行一些计算,并返回数组 x
,大小为 a*b
。
将此函数构建到共享库后
myfunction.so
,我在Python中调用它,如下所示:
from ctypes import *
libc = CDLL('myfunction.so')
myfunction = libc.myfunction
myfunction.restype = POINTER(c_double)
myfunction.argtypes = [POINTER(c_double), POINTER(c_double),
c_int, c_int,
c_int, c_int]
y = POINTER(c_double)()
z = POINTER(c_double)()
n_y = c_int()
n_z = c_int()
a = 18
b = 18
x = myfunction(byref(y), byref(z),
byref(n_y), byref(n_z),
c_int(a), c_int(b))
运行此脚本时出现错误:
ctypes.ArgumentError:参数 3: : 错误 类型
所以
c_int
的 n_y
类型是不正确的。我应该放什么来代替?
非常感谢您的帮助!
更新
按照@GiacomoAlzetta 和@CristiFati 的建议,我已更改代码以使用指针而不是按引用传递,如下所示。
(
y
和z
很相似,所以让我省略z
)
extern "C" {
double* myfunction(double** y, int* n_y, int a, int b)
{
vector<double> _x;
vector<double> _y;
// Call some external C++ function
cpp_function(_x, _y, a, b);
// Convert vectors back to arrays
double* x = &_x[0]; // or x = _x.data();
*y = &_y[0];
*n_y = static_cast<int>(_y.size());
return x;
}
}
现在在C++中,我按如下方式调用上面的函数:
double* y;
int n_y;
int a = 18;
int b = 18;
double* x = myfunction(&y, &n_y, a, b);
有效。在 Python 中:
from ctypes import *
libc = CDLL('myfunction.so')
myfunction = libc.myfunction
myfunction.restype = POINTER(c_double)
myfunction.argtypes = [POINTER(POINTER(c_double)), POINTER(c_int),
c_int, c_int]
y = POINTER(POINTER(c_double))()
n_y = POINTER(c_int)()
a = 18
b = 18
x = myfunction(y, n_y, c_int(a), c_int(b))
产生了
Segmentation fault
错误,发生在该行
*y = &_y[0];
谢谢您的帮助!
你就快到了。
同时,请密切关注 [Python.Docs]:ctypes - Python 的外部函数库。
请记住,无论您身在何处,都应该以相同的方式处理指针参数(实际上它适用于所有指针参数,但对于非指针参数来说事情很简单)。
换句话说,您在 C 中所做的操作(实例化变量并将其指针传递给函数),您也应该在 Python 中执行操作(而不是 实例化变量指针并将其传递给函数)。
翻译成代码,你应该修改初始化y、n_y以及函数(myfunction)调用的方式:
>>> #from ctypes import * # Anti-pattern. Don't use it
>>> import ctypes as cts
>>>
>>> y = cts.POINTER(cts.c_double)() # Instantiate simple pointer
>>> n_y = cts.c_int()
>>> a = 18
>>> b = 18
>>> x = myfunction(cts.pointer(y), cts.pointer(n_y), a, b)
注释:
向量是局部变量,当函数返回时会被释放,因此你需要保留内存。
这是为了保留内存而重新编写的 C++ 代码。我刚刚用一些数据创建了一些局部变量,因为您的示例不完整:
#define API __declspec(dllexport) // Windows-specific export
#include <cstdlib>
#include <vector>
using namespace std;
extern "C" {
API double* myfunction(double* &y, double* &z, int &n_x, int &n_y, int &n_z)
{
vector<double> _x {1.1,2.2,3.3};
vector<double> _y {4.4,5.5};
vector<double> _z {6.6,7.7,8.8,9.9};
// Allocate some arrays to store the vectors.
double* x = new double[_x.size()];
y = new double[_y.size()];
z = new double[_z.size()];
memcpy(x,_x.data(),_x.size() * sizeof(double));
memcpy(y,_y.data(),_y.size() * sizeof(double));
memcpy(z,_z.data(),_z.size() * sizeof(double));
n_x = static_cast<int>(_x.size());
n_y = static_cast<int>(_y.size());
n_z = static_cast<int>(_z.size());
return x;
}
// A function to free up the memory.
API void myfree(double* x, double* y, double* z)
{
delete [] x;
delete [] y;
delete [] z;
}
}
Python:
from ctypes import *
dll = CDLL('test')
dll.myfunction.argtypes = (POINTER(POINTER(c_double)),
POINTER(POINTER(c_double)),
POINTER(c_int),
POINTER(c_int),
POINTER(c_int))
dll.myfunction.restype = POINTER(c_double)
dll.myfree.argtypes = POINTER(c_double),POINTER(c_double),POINTER(c_double)
dll.myfree.restype = None
# Helper function to allocate storage for return arrays
def myfunction():
y = POINTER(c_double)() # create an instance of a C double*
z = POINTER(c_double)()
n_x = c_int() # and instances of C int
n_y = c_int()
n_z = c_int()
# Pass them all by reference so new values can be returned
x = dll.myfunction(byref(y),byref(z),byref(n_x),byref(n_y),byref(n_z))
# Copies the data into Python lists
a = x[:n_x.value]
b = y[:n_y.value]
c = z[:n_z.value]
# Free the C arrays and return the Python lists.
dll.myfree(x,y,z)
return a,b,c
x,y,z = myfunction()
print(x,y,z)
输出:
[1.1, 2.2, 3.3] [4.4, 5.5] [6.6, 7.7, 8.8, 9.9]
请注意,正在进行大量复制。查看