【问题标题】:How to expose a Rust `Vec<T>` to FFI?如何将 Rust `Vec<T>` 暴露给 FFI?
【发布时间】:2017-01-06 14:03:38
【问题描述】:

我正在尝试构造一对元素:

  • array: *mut T
  • array_len: usize

array 旨在拥有数据

但是,Box::into_raw 将返回 *mut [T]。我找不到任何关于将原始指针转换为切片的信息。它在内存中的布局是什么?我如何从 C 中使用它?我应该转换为*mut T 吗?如果有,怎么做?

【问题讨论】:

    标签: rust ffi


    【解决方案1】:

    如果你只是想让某个 C 函数可变地借用 Vec,你可以这样做:

    extern "C" {
        fn some_c_function(ptr: *mut i32, len: ffi::size_t);
    }
    
    fn safe_wrapper(a: &mut [i32]) {
        unsafe {
            some_c_function(a.as_mut_ptr(), a.len() as ffi::size_t);
        }
    }
    

    当然,C 函数不应将此指针存储在其他地方,因为这会破坏别名假设。

    如果您想将数据的所有权“传递”给 C 代码,您可以这样做:

    use std::mem;
    
    extern "C" {
        fn c_sink(ptr: *mut i32, len: ffi::size_t);
    }
    
    fn sink_wrapper(mut vec: Vec<i32>) {
        vec.shrink_to_fit();
        assert!(vec.len() == vec.capacity());
        let ptr = vec.as_mut_ptr();
        let len = vec.len();
        mem::forget(vec); // prevent deallocation in Rust
                          // The array is still there but no Rust object
                          // feels responsible. We only have ptr/len now
                          // to reach it.
        unsafe {
            c_sink(ptr, len as ffi::size_t);
        }
    }
    

    这里,C 函数“取得所有权”,因为我们期望它最终将指针和长度返回给 Rust,例如,通过调用 Rust 函数来释放它:

    #[no_mangle]
    /// This is intended for the C code to call for deallocating the
    /// Rust-allocated i32 array.
    unsafe extern "C" fn deallocate_rust_buffer(ptr: *mut i32, len: ffi::size_t) {
        let len = len as usize;
        drop(Vec::from_raw_parts(ptr, len, len));
    }
    

    因为Vec::from_raw_parts 需要三个参数,一个指针、一个大小和一个容量,我们要么必须以某种方式跟踪容量,要么在将指针和长度传递给 C 函数之前使用 Vec 的 shrink_to_fit .不过,这可能涉及重新分配。

    【讨论】:

    • 这就是我最终使用的:github.com/maidsafe/safe_core/pull/321/…>。除了assert!,我正在考虑使用它,但我没有足够的信心/说服力。
    【解决方案2】:

    您可以通过use [T]::as_mut_ptr 直接从Vec&lt;T&gt;Box&lt;[T]&gt; 或任何其他DerefMut-to-slice 类型获取*mut T 指针。

    use std::mem;
    
    let mut boxed_slice: Box<[T]> = vector.into_boxed_slice();
    
    let array: *mut T = boxed_slice.as_mut_ptr();
    let array_len: usize = boxed_slice.len();
    
    // Prevent the slice from being destroyed (Leak the memory).
    mem::forget(boxed_slice);
    

    【讨论】:

    • 一旦vector 被销毁,array 是否仍然有效?这个想法是 array 将拥有数据(我会更新问题)。
    • @vinipsmaker:不。因此,请防止向量被forgetting 破坏。查看更新。
    • 抱歉,我对解除分配代码在这种方法中的工作方式感到困惑。 into_boxed_slice 将返回...内存中的布局是什么? boxed_slice.as_mut_ptr() 保证返回指向第一个字符的指针?如何转换回 Box&lt;[T]&gt; 以便解除分配?
    • @vinipsmaker: (1) 未指定布局。当前实现使用(ptr, len)。 (2) 也许你应该问一个新问题。但是你可以试试slice::from_raw_parts_mutBox::from_raw,或者使用Vec::from_raw_parts,但是你也需要通过容量。
    • slice::from_raw_parts + Box::from_raw 在这里会好吗? Box::from_raw 不是获得指向堆栈分配切片的指针而不是原始切片吗?还是Box&lt;[T]&gt;是特例?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-26
    相关资源
    最近更新 更多