Rust 我可以将字节数组反序列化为结构吗?

Rust 我可以将字节数组反序列化为结构吗?,rust,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;

我正在从套接字读取一系列字节,需要将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);

}
使用std::mem;
#[导出(调试)]
构造事物{
x:u8,
y:u16,
}
fn main(){
让数组=[22作为u8,76作为u8,34作为u8];
让福巴:事情;
不安全{
foobar=mem::transmute::(数组);
}
println!(“{:?}”,foobar);
}

我得到的错误是,
foobar
是32位,而
array
是24位。
foobar
不应该是24位(8+16=24)?

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

x
padding
y
y
请注意,交换
x
y
的顺序没有任何帮助,因为Rust的结构内存布局实际上是未定义的(因此仍然是32位,原因很简单,只是在编译器中很简单)。如果你依赖它,你将得到未定义的行为

对齐的原因在中进行了解释

通过将属性
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),
};
让foobar=Things{
x:数组[0],

y:((数组[1]作为u16)结构中的每个项之间是否总是有8位的填充?不,填充只是不相关的内容。填充的存在只是因为另一个字段是空的aligned@Fluffy不一定。如果
x
也是
u16
,则不需要填充。如果
x
仍然是
u8
,并且您有一个
x2
字段t这也是
u8
x
y
之间,您仍然不需要填充。您知道为什么吗?(注意,您可以查找结构对齐,而不考虑语言-原因总是一样的。)@Fluffy如果所有字段的大小都相同,则不会更快。逻辑是,
u8
是8位对齐的,
u16
是16位对齐的。这会在两者之间创建必要的8位空间。您可以选择自己使用该空间(通过将第一个字段扩展到16位或引入中间8位字段)或者您可以不使用它(称为填充),但不管您是否打算将其命名为字段,编译器都会将8位空间放在那里。(除非您明确要求使用压缩结构,如回答中所述。)@Fluffy,即使您以某种方式解决对齐问题(这不太可能),您仍然会遇到字节顺序的问题,如果您需要通过网络传递数据,这一点很重要。将字节数组重新解释为结构本身就不可移植。这就是为什么有很多序列化格式可用。请注意,这与许多其他答案的问题相同:它没有考虑对齐方式t、 目标类型中可能存在填充(对于
u64
,这不是问题),或endianness。不需要在指针上使用transmute,只需强制转换指针。这将防止指针和指向指针的指针之间的意外转换,正如强制转换有些类型检查一样。正如其他人所说,这是不推荐的,但这正是OP所要求的,在技术上是正确的。endianness和其他细节o如果有人想走这条路,要小心。
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);
}