假设我们有一个结构体,其所有字段的类型大小相同:
struct Homogeneous {
a: u64,
b: u64,
c: u64,
d: u64
}
我们有一种“安全”的方法,可以从字节数组构建它:
impl From<[u8; 32]> for Homogeneous {
fn from(slice: [u8; 32]) -> Self {
// helper macro to convert slice of u8s into u64
macro_rules! to_u64 {
($slice: expr, $at: expr) => {{
let ss = &$slice[$at..$at + 8];
let mut buf = [0u8; 8];
buf.copy_from_slice(&ss);
u64::from_ne_bytes(buf)
}};
}
Self {
a: to_u64!(bytes, 0),
b: to_u64!(bytes, 8),
c: to_u64!(bytes, 16),
d: to_u64!(bytes, 24),
}
}
}
这一切都很好,而且它也能正常运作。问题在于不安全的解决方案(使用transmute)是否更有效(更安全?),同时反向转换是否不会因为编译器优化重排序结构体字段而导致 UB?
impl From<[u8; 32]> for Homogeneous {
fn from(slice: [u8; 32]) -> Self {
unsafe { std::mem::transmute(slice) };
}
}
impl From<Homogeneous> for [u8; 32] {
fn from(h: Homogeneous) -> Self {
unsafe { std::mem::transmute(h) }
}
}
使用 Rust 1.57 编译器,这些转换在我的 x86 处理器上运行良好。我想知道它们是否会始终如此,无论架构/编译器如何。
let to_bytes = |i| u64::from_ne_bytes(bytes[i..][..8].try_into().unwrap()); Self { a: to_bytes(0), b: to_bytes(8), … }
。生成的字节码相同。 - Caesar