我有一个未知大小的字节缓冲区,我想创建一个指向缓冲区开头的内存的本地结构变量。按照我在 C 中所做的事情,我在 Rust 中尝试了很多不同的事情,但不断出错。这是我最近的尝试:
use std::mem::{size_of, transmute};
#[repr(C, packed)]
struct MyStruct {
foo: u16,
bar: u8,
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
let buffer = v.as_slice();
let s: MyStruct = unsafe { transmute(buffer[..size_of::<MyStruct>()]) };
}
我收到错误:
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> src/main.rs:12:42
|
12 | let s: MyStruct = unsafe { transmute(buffer[..size_of::<MyStruct>()]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
slice::align_to
。这会创建一个 &MyStruct
:
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct MyStruct {
foo: u16,
bar: u8,
}
fn main() {
let v = vec![1u8, 2, 3];
// I copied this code from Stack Overflow
// without understanding why this case is safe.
let (head, body, _tail) = unsafe { v.align_to::<MyStruct>() };
assert!(head.is_empty(), "Data was not aligned");
let my_struct = &body[0];
println!("{:?}", my_struct);
}
在这里,使用
align_to
将一些字节转换为 MyStruct
是安全的,因为我们已经使用了 repr(C, packed)
并且 MyStruct
中的所有类型都可以是任意字节。
另请参阅:
我放弃了转化的东西。 Rust 中的
*mut
(原始指针)与 C 指针非常相似,所以这很简单:
#[repr(C, packed)] // necessary
#[derive(Debug, Copy, Clone)] // not necessary
struct MyStruct {
foo: u16,
bar: u8,
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
let buffer = v.as_slice();
let mut s_safe: Option<&MyStruct> = None;
let c_buf = buffer.as_ptr();
let s = c_buf as *mut MyStruct;
unsafe {
let ref s2 = *s;
s_safe = Some(s2);
}
println!("here is the struct: {:?}", s_safe.unwrap());
}
unsafe
标签不是开玩笑,但我使用它的方式,我知道我的缓冲区已满,并在稍后采取涉及字节顺序的适当预防措施。
我目前正在使用:
unsafe { transmute::<[u8; 0x70], Header>(header_data) };
当然不安全,但效果很好。
let mut header_data = [0; 0x70];
reader.seek(SeekFrom::Start(0))?;
reader.read_exact(&mut header_data)?;
let header = unsafe { transmute::<[u8; 0x70], Header>(header_data) };