在没有 std 的情况下将 *mut u8 转换为 &[u8]
casting *mut u8 to &[u8] without std
我正在为 WebAssembly 编写 Rust 代码来处理来自 JavaScript 土地的字符串。
由于 WebAssembly 没有真正的字符串类型,我试图传递一个指向 WebAssembly 内存对象的指针,该对象指向 UTF-8 编码的字符串。
#[no_mangle]
pub extern "C" fn check(ptr: *mut u8, length: u32) -> u32 {
unsafe {
let buf: &[u8] = std::slice::from_raw_parts(ptr, length as usize);
// do some operations on buf
0
}
}
它工作正常,希望我必须依赖 std
板条箱,它将最终二进制文件膨胀到大约 600KB。
有什么方法可以摆脱 std::slice::from_raw_parts
但仍然能够将原始指针转换为切片?
你不能将原始指针转换为切片,因为在 Rust 中,切片不仅仅是一个指针,它是一个指针 并且 一个大小(否则它可能不安全).
如果不想使用std
,可以使用core
crate:
extern crate core;
#[no_mangle]
pub extern "C" fn check(ptr: *mut u8, length: u32) -> u32 {
unsafe {
let buf: &mut [u8] = core::slice::from_raw_parts_mut(ptr, length as usize);
}
// do some operations on buf
0
}
core
crate 是 std
crate 中适合嵌入式的部分,即 没有所有需要分配的东西。
可以手动构造类似于切片的东西,它是一个胖指针,由一个瘦指针和一个长度组成。然后将 pointer-to-this-construct 转换为 pointer-to-slice。
这种方法不仅不安全,它还依赖于 Rust 内部结构(切片的内存布局),这些内部结构不能保证在编译器版本之间保持稳定,甚至是我认为的系统。如果您想确保您的代码在未来正常工作,@Boiethios 的回答是可行的方法。但是,出于教育目的,下面的代码可能仍然很有趣:
unsafe fn make_slice<'a>(ptr: *const u8, len: usize) -> &'a [u8] {
// place pointer address and length in contiguous memory
let x: [usize; 2] = [ptr as usize, len];
// cast pointer to array as pointer to slice
let slice_ptr = &x as * const _ as *const &[u8];
// dereference pointer to slice, so we get a slice
*slice_ptr
}
fn main() {
let src: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
let raw_ptr = &src[1] as *const u8;
unsafe {
println!("{:?}", make_slice(raw_ptr, 3)); // [2, 3, 4]
}
}
(使用 Rust Stable 1.26.2 在 playground 上测试)
我正在为 WebAssembly 编写 Rust 代码来处理来自 JavaScript 土地的字符串。
由于 WebAssembly 没有真正的字符串类型,我试图传递一个指向 WebAssembly 内存对象的指针,该对象指向 UTF-8 编码的字符串。
#[no_mangle]
pub extern "C" fn check(ptr: *mut u8, length: u32) -> u32 {
unsafe {
let buf: &[u8] = std::slice::from_raw_parts(ptr, length as usize);
// do some operations on buf
0
}
}
它工作正常,希望我必须依赖 std
板条箱,它将最终二进制文件膨胀到大约 600KB。
有什么方法可以摆脱 std::slice::from_raw_parts
但仍然能够将原始指针转换为切片?
你不能将原始指针转换为切片,因为在 Rust 中,切片不仅仅是一个指针,它是一个指针 并且 一个大小(否则它可能不安全).
如果不想使用std
,可以使用core
crate:
extern crate core;
#[no_mangle]
pub extern "C" fn check(ptr: *mut u8, length: u32) -> u32 {
unsafe {
let buf: &mut [u8] = core::slice::from_raw_parts_mut(ptr, length as usize);
}
// do some operations on buf
0
}
core
crate 是 std
crate 中适合嵌入式的部分,即 没有所有需要分配的东西。
可以手动构造类似于切片的东西,它是一个胖指针,由一个瘦指针和一个长度组成。然后将 pointer-to-this-construct 转换为 pointer-to-slice。
这种方法不仅不安全,它还依赖于 Rust 内部结构(切片的内存布局),这些内部结构不能保证在编译器版本之间保持稳定,甚至是我认为的系统。如果您想确保您的代码在未来正常工作,@Boiethios 的回答是可行的方法。但是,出于教育目的,下面的代码可能仍然很有趣:
unsafe fn make_slice<'a>(ptr: *const u8, len: usize) -> &'a [u8] {
// place pointer address and length in contiguous memory
let x: [usize; 2] = [ptr as usize, len];
// cast pointer to array as pointer to slice
let slice_ptr = &x as * const _ as *const &[u8];
// dereference pointer to slice, so we get a slice
*slice_ptr
}
fn main() {
let src: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
let raw_ptr = &src[1] as *const u8;
unsafe {
println!("{:?}", make_slice(raw_ptr, 3)); // [2, 3, 4]
}
}
(使用 Rust Stable 1.26.2 在 playground 上测试)