如何将 Rust `Vec<T>` 暴露给 FFI?
Posted
技术标签:
【中文标题】如何将 Rust `Vec<T>` 暴露给 FFI?【英文标题】:How to expose a Rust `Vec<T>` to FFI? 【发布时间】:2017-01-06 14:03:38 【问题描述】:我正在尝试构造一对元素:
array: *mut T
array_len: usize
array
旨在拥有数据
但是,Box::into_raw
将返回 *mut [T]
。我找不到任何关于将原始指针转换为切片的信息。它在内存中的布局是什么?我如何从 C 中使用它?我应该转换为*mut T
吗?如果有,怎么做?
【问题讨论】:
【参考方案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<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);
【讨论】:
一旦vector
被销毁,array
是否仍然有效?这个想法是 array
将拥有数据(我会更新问题)。
@vinipsmaker:不。因此,请防止向量被forget
ting 破坏。查看更新。
抱歉,我对解除分配代码在这种方法中的工作方式感到困惑。 into_boxed_slice
将返回...内存中的布局是什么? boxed_slice.as_mut_ptr()
保证返回指向第一个字符的指针?如何转换回 Box<[T]>
以便解除分配?
@vinipsmaker: (1) 未指定布局。当前实现使用(ptr, len)
。 (2) 也许你应该问一个新问题。但是你可以试试slice::from_raw_parts_mut
和Box::from_raw
,或者使用Vec::from_raw_parts
,但是你也需要通过容量。
slice::from_raw_parts
+ Box::from_raw
在这里会好吗? Box::from_raw
不是获得指向堆栈分配切片的指针而不是原始切片吗?还是Box<[T]>
是特例?以上是关于如何将 Rust `Vec<T>` 暴露给 FFI?的主要内容,如果未能解决你的问题,请参考以下文章
Rust Diesel 原始 SQL 给出错误“`std::result::Result<Vec<T>,diesel::result::Error>` 所需的类型注释”