我正在从一个套接字读取一系列字节,我需要将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
请注意,交换
x
和y
的顺序并没有帮助,因为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这样的板条箱可以简化从字节读取不同大小和长度的过程。