如何将u32数组转换为u8数组?

  • 本文关键字:数组 u8 转换 u32 rust
  • 更新时间 :
  • 英文 :


我想将[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)。

最新更新