我正在从一个套接字读取一系列字节,我需要将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是32位,而array是24位。foobar不应该是24位(8+16=24)?

最佳答案

这里的问题是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这样的板条箱可以简化从字节读取不同大小和长度的过程。

10-02 02:30
查看更多