Python ctypes : pass argument by reference error

标签 python ctypes

我有一个 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,并返回一个大小为 a*b 的数组 x

将此函数构建到共享库 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: argument 3: : wrong type

所以n_yc_int类型是不正确的。我应该放什么?

非常感谢您的帮助!


更新

按照@GiacomoAlzetta 和@CristiFati 的建议,我更改了我的代码以使用指针而不是通过引用传递,如下所示。

(yz 相似所以让我省略 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 3.Docs]: ctypes - A foreign function library for Python .

请记住,无论您身在何处,都应该以相同的方式处理指针参数(实际上它适用于所有指针参数,但对于非指针参数,事情很简单)。

换句话说,您在 C 中所做的事情(实例化一个变量 并将其指针传递给函数),您也应该这样做在 Python 中(代替 实例化变量指针 并将其传递 给函数).

转换为代码,您应该修改初始化yn_y 和函数(myfunction) 调用的方式:

>>> from ctypes import *  # Anti-pattern. Don't ever use it
>>>
>>> y = POINTER(c_double)()
n_y = c_int()
a = 18
b = 18
x = myfunction(pointer(y), pointer(n_y), a, b)

注意事项:

  • 我在评论中所说的(未定义的行为 因为向量存在于堆栈中并且在退出函数时将被销毁)仍然有效。要修复它:
    • 在返回之前在堆上分配数据 (malloc/new)(完成后,您还需要释放它(free/删除),以避免内存泄漏)
    • 让它们静态

一些远程连接的例子:

关于Python ctypes : pass argument by reference error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52204971/

相关文章:

python - 如何在 ctypes 中取消引用 void*?

Python:获取和保存屏幕截图的最快方法

python - 如何使用不会引起 PEP 警告的选项卡

python - 在 Pyramid 中,如何根据上下文内容使用不同的渲染器?

python - django 如何从子关系中获取字段到父模板中

python - if __name__ == '__main__' 的风格指南是什么?

python - 从对象列表创建 pandas Dataframe

python - 多处理 Python 中的共享数组

python - 使用 ctypes 和 SSE/AVX 有时会出现段错误

python - 为什么 ctypes 将 Python 列表转换为 C 数组的速度如此之慢?