【发布时间】:2017-01-06 14:03:38
【问题描述】:
我正在尝试构造一对元素:
array: *mut Tarray_len: usize
array 旨在拥有数据
但是,Box::into_raw 将返回 *mut [T]。我找不到任何关于将原始指针转换为切片的信息。它在内存中的布局是什么?我如何从 C 中使用它?我应该转换为*mut T 吗?如果有,怎么做?
【问题讨论】:
我正在尝试构造一对元素:
array: *mut Tarray_len: usizearray 旨在拥有数据
但是,Box::into_raw 将返回 *mut [T]。我找不到任何关于将原始指针转换为切片的信息。它在内存中的布局是什么?我如何从 C 中使用它?我应该转换为*mut T 吗?如果有,怎么做?
【问题讨论】:
如果你只是想让某个 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 .不过,这可能涉及重新分配。
【讨论】:
assert!,我正在考虑使用它,但我没有足够的信心/说服力。
您可以通过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 将拥有数据(我会更新问题)。
forgetting 破坏。查看更新。
into_boxed_slice 将返回...内存中的布局是什么? boxed_slice.as_mut_ptr() 保证返回指向第一个字符的指针?如何转换回 Box<[T]> 以便解除分配?
(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]>是特例?