我可以使用字节数组并将其反序列化为结构吗?

时间:2016-03-17 13:11:43

标签: rust

我从套接字读取一系列字节,我需要将n个字节的每个段作为项目放在一个结构中。

use std::mem;

#[derive(Debug)]
struct Things {
    x: u8,
    y: u16,
}

fn main() {
    let array = [22 as u8, 76 as u8, 34 as u8];
    let foobar: Things;
    unsafe {
        foobar = mem::transmute::<[u8; 3], Things>(array);
    }

    println!("{:?}", foobar);

}

foobar为24位时,我收到的错误表明array为32位。那不是foobar是24位(8 + 16 = 24)吗?

2 个答案:

答案 0 :(得分:13)

这里的问题是y字段是16位对齐的。所以你的内存布局实际上是

x
padding
y
y

请注意,交换xy的顺序并不会有帮助,因为Rust的结构内存布局实际上是未定义的(因此仍然是32位,但无缘无故,但简单的编译器)。如果您依赖它,您将得到未定义的行为。

Purpose of memory alignment解释了对齐的原因。

您可以通过向结构添加属性repr(packed)来防止对齐发生,但是您将失去性能并且能够引用字段:

#[repr(packed)]
struct Things {
    x: u8,
    y: u16,
}

最好的方法是不要使用transmute,而是手动提取值并希望优化器加快速度:

let foobar = Things {
    x: array[0],
    y: ((array[1] as u16) << 8) | (array[2] as u16),
};

byteorder这样的包可以简化从字节中读取不同大小和字节序的过程。

答案 1 :(得分:0)

use std::mem;

fn main() {
    let bytes = vec!(0u8, 1u8,2u8, 3, 4, 5, 6, 7, 8, 9, 0xffu8, );


    let data_ptr: *const u64 = unsafe { mem::transmute(bytes[0..4].as_ptr()) };

    let data: u64 = unsafe { *data_ptr };

    println!("{:#x}", data);
}