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

vin*_*ker 15 ffi rust

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

  • array: *mut T
  • array_len: usize

array 旨在拥有数据

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

sel*_*tze 13

如果你只是想要一些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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,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));
}
Run Code Online (Sandbox Code Playgroud)

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


ken*_*ytm 9

你可以使用[T]::as_mut_ptr,以获得*mut T直接从指针Vec<T>,Box<[T]>或任何其他DerefMut到切片类型.

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);
Run Code Online (Sandbox Code Playgroud)

  • @vinipsmaker:(1)未指定布局.当前实现使用`(ptr,len)`.(2)也许你应该问一个新问题.但你可以尝试`slice :: from_raw_parts_mut`和`Box :: from_raw`,或者使用`Vec :: from_raw_parts`,但你也需要传递容量. (2认同)