如何将 Rust `Vec<T>` 暴露给 FFI?

How to expose a Rust `Vec<T>` to FFI?

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

array意在拥有数据

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

您可以 use [T]::as_mut_ptr 直接从 Vec<T>Box<[T]> 或任何其他 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);

如果你只是想让一些 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 函数不应将此指针存储在其他地方,因为那样会破坏别名假设。

如果你想 "pass ownership" 数据到 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 函数 "takes ownership" 在某种意义上我们期望它最终 return 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 需要三个参数,一个指针,一个大小和一个容量,我们要么必须以某种方式跟踪容量,要么我们在传递指针之前使用 Vec 的 shrink_to_fit和 C 函数的长度。不过,这可能涉及重新分配。