我想将[u32; 4]
转换为[u8; 16]
。
我知道可以使用位操作从4u32
中获得16u8
。但我想把数组转换成原位。如何使用安全Rust或不安全Rust来做到这一点?
let buffer: [u32; 4] = [1, 2, 3, 4];
let hash: [u8; 16]; // how to convert from buffer to hash?
背景信息:我正在计算一个128位的哈希值,其中[u32; 4]
是一个持有4u32
的缓冲区。我想把数组转换为[u8; 16]
,作为最终的哈希值。
您可能想要进行转换,但我建议不要这样做,主要是因为端序,即最终输出将取决于您的机器是大端序还是小端序:
pub fn convert(data: &[u32; 4]) -> [u8; 16] {
unsafe { std::mem::transmute(*data) }
}
我就用这种无聊的方式(playground):
pub fn convert(data: &[u32; 4]) -> [u8; 16] {
let mut res = [0; 16];
for i in 0..4 {
res[4*i..][..4].copy_from_slice(&data[i].to_le_bytes());
}
res
}
如果需要大端序,则将to_le_bytes()
更改为to_be_bytes()
。或者使用to_ne_bytes()
来获得本地端序,如果你不在乎的话。
如果您担心性能(但为什么要担心呢?)使用本机端序为x86_64
生成的代码是最好的:
playground::convert:
movq %rdi, %rax
movups (%rsi), %xmm0
movups %xmm0, (%rdi)
retq
使用unsafe
,可以很容易地使用transmute()
:
pub fn convert(v: [u32; 4]) -> [u8; 16] {
unsafe { std::mem::transmute(v) }
}
我认为没有外部板条箱就没有有效安全的方法。如果你可以采用外部板条箱,你可以使用bytemuck::cast()
:
pub fn convert(v: [u32; 4]) -> [u8; 16] {
bytemuck::cast(v)
}
对当前被接受的答案采取稍微简单/更习惯的做法:
pub fn convert(source: &[u32; 4]) -> [u8; 16] {
let mut dest = [0; 16];
for (dest_c, source_e) in dest.chunks_exact_mut(4).zip(source.iter()) {
dest_c.copy_from_slice(&source_e.to_le_bytes())
}
dest
}
基于反汇编,它似乎生成了更简单的ASM,可能是因为完全基于迭代器的迭代有更强的假设(我已经检查了一个具有64k u32项的数组,但我还没有彻底分析ASM)。