在Rust中将u8缓冲区转化为结构体

py49o6xq  于 2023-03-08  发布在  其他
关注(0)|答案(4)|浏览(144)

我有一个未知大小的字节缓冲区,我想创建一个指向缓冲区起始内存的局部结构变量。按照我在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>
kuarbcqp

kuarbcqp1#

如果你不想把数据复制到结构体中,而是把它留在原处,你可以使用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中的所有类型都可以是任意字节。
另见:

ycl3bljg

ycl3bljg2#

您可以使用raw pointers上的方法和std::ptr中的函数直接在适当的位置读取/写入对象。

在您的情况下:

fn main() {
    let v: Vec<u8> = vec![1, 2, 3];
    let s: MyStruct = unsafe { std::ptr::read(v.as_ptr() as *const _) };
    println!("here is the struct: {:?}", s);
}

我鼓励您将其 Package 在一个可重用的方法中,并在尝试读取之前对源缓冲区执行长度检查。

w51jfk4q

w51jfk4q3#

我放弃了变形的东西。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标记不是开玩笑的,但我使用它的方式,我知道我的缓冲区已满,并采取适当的预防措施,涉及字节序稍后。

tcomlyy6

tcomlyy64#

我目前正在使用:

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) };

相关问题