首页 文章

使用ctypes在Python中使用Rust返回的数组

提问于
浏览
9

我有一个返回 array 的Rust函数,我想在 Python 中使用这个数组,它可能是 listnumpy.array 它并不重要 .

我的Rust功能如下所示:

#[no_mangle]
pub extern fn make_array() -> [i32; 4] {
    let my_array: [i32; 4] = [1,2,3,4];
    return my_array;
}

我试图用Python调用它:

In [20]: import ctypes

In [21]: from ctypes import cdll

In [22]: lib = cdll.LoadLibrary("/home/user/RustStuff/embed/target/release/libembed.so")

In [23]: lib.make_array.restype = ctypes.ARRAY(ctypes.c_int32, 4)

In [24]: temp = lib.make_array()

In [25]: [i for i in temp]
Out[25]: [1, 2, -760202930, 32611]

我究竟做错了什么?为什么我的输出不是 [1,2,3,4] ?为什么我的前两个元素是正确的,另外两个元素是垃圾?

我无法在 ctypes.ARRAY 上找到任何好的文档,所以我只是选择了看起来正确的文档,这很可能就是问题所在 .

2 回答

  • 1

    正如其他人所说,你无法真正正确地返回一个固定大小的数组 . 但是你可以通过将数组包装在一个结构中来欺骗ctypes做正确的事情:

    import ctypes
    
    class Int32_4(ctypes.Structure):
        _fields_ = [("array", ctypes.c_int32 * 4)]
    
    lib = ctypes.CDLL("embed.dll")
    lib.make_array.restype = Int32_4
    
    temp = lib.make_array()
    
    print(temp.array[:])
    

    这导致我的机器上的 [1, 2, 3, 4] .

    Addendum :这是"trick"因为我们正在利用C可以做什么和Rust可以做什么之间的区别 . C不会让你按值返回一个固定大小的数组,但Rust会这样,它的工作方式与返回用户定义的结构相同 .

    因此,我们做了C允许的事情:返回一个恰好包含固定大小数组的结构 . 这个很好,它与Rust正在使用的布局相匹配 .

    当然,这也有些愚蠢,因为我并不完全相信这是明确定义的行为 . 如果您想要更安全,可以更改Rust端的返回类型以匹配C:

    #[repr(C)]
    struct Int32_4 {
        array: [i32; 4]
    }
    
  • 5

    我同意@delnan所说的 - you can't return fixed-size arrays in C . 一个主要的不兼容性是Rust数组知道它们的大小,但C数组不知道 . 您将需要遵守每个其他C程序如何完成此操作 - 分别返回指针和长度 . 相比之下,Rust不是一种不错的现代语言吗?

    我偷了并修改了一些Python代码from another answer

    import ctypes
    
    from ctypes import cdll
    
    lib = cdll.LoadLibrary("libarray.dylib")
    lib.make_array.restype = ctypes.POINTER(ctypes.c_int32 * 4)
    
    print [i for i in lib.make_array().contents]
    

    这适用于这个Rust代码:

    static ARRAY: [i32; 4] = [1,2,3,4];
    
    #[no_mangle]
    pub extern fn make_array() -> *const i32 {
        ARRAY.as_ptr()
    }
    

    在这里,我们正在做最简单的事情,创建一个将在程序的整个长度内存活并返回对其数据的引用的数组 . 在您的真实程序中,您可能需要更加小心,以确保您的 Vec<i32>&[i32] 严格超过Python代码指针的持续时间,否则您将导致内存损坏 .

相关问题