暂时将 [u8] 转化为 [u16]

Temporarily transmute [u8] to [u16]

我有一个 [u8; 16384] 和一个 u16。我如何 "temporarily transmute" 数组以便我可以一次设置两个 u8,第一个到最低有效字节,第二个到最高有效字节?

显而易见、安全且便携的方法是只使用数学。

fn set_u16_le(a: &mut [u8], v: u16) {
    a[0] = v as u8;
    a[1] = (v >> 8) as u8;
}

如果您想要更高级别的界面,可以使用 byteorder 板条箱来实现。

你绝对应该使用transmute[u8]变成[u16],因为这并不能保证[=22] =]关于字节顺序的任何东西。

,你可能真的不应该使用 unsafe 代码来重新解释记忆……但如果你愿意,你可以。

如果你真的想走那条路,你应该注意几个问题:

  • 您可能遇到对齐问题。如果您只是从某处获取 &mut [u8] 并将其转换为 &mut [u16],它可能会引用一些未正确 aligned 的内存区域作为u16。根据您 运行 此代码所在的计算机,这种未对齐的内存访问可能是非法的。在这种情况下,程序可能会以某种方式中止。例如,CPU 可以生成某种信号,操作系统响应该信号以终止进程。
  • 它将不可携带。即使没有对齐问题,你也会在不同的机器上得到不同的结果(小端和大端机器)。

如果你可以切换它(创建一个 u16 数组并临时在字节级别处理它),你将解决潜在的内存对齐问题:

/// warning: The resulting byte view is system-specific
unsafe fn raw_byte_access(s16: &mut [u16]) -> &mut [u8] {
    use std::slice;
    slice::from_raw_parts_mut(s16.as_mut_ptr() as *mut u8, s16.len() * 2)
}

在大端机器上,这个函数不会做你想做的;你想要一个 little-endian 字节顺序。您只能将其用作小端机器的优化,并且需要坚持使用像 DK 这样的解决方案来用于大端或混合端机器。

slice::align_to and slice::align_to_mut are stable as of Rust 1.30. These functions handle the alignment concerns that 提出来。

大端和小端问题仍然是您的后顾之忧。您可以使用 u16::to_le 之类的方法来帮助解决这个问题。但是,我无法使用 big-endian 计算机进行测试。

fn example(blob: &mut [u8; 16], value: u16) {
   // I copied this example from Stack Overflow without providing 
   // rationale why my specific case is safe.
   let (head, body, tail) = unsafe { blob.align_to_mut::<u16>() };

   // This example simply does not handle the case where the input data
   // is misaligned such that there are bytes that cannot be correctly
   // reinterpreted as u16.
   assert!(head.is_empty());
   assert!(tail.is_empty());

   body[0] = value
}

fn main() {
   let mut data = [0; 16];
   example(&mut data, 500);
   println!("{:?}", data);
}