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

Shi*_*ien 5 arrays casting unsafe rust

我有一个[u8; 16384]和一个u16.我如何"暂时转换"数组,以便我可以同时设置两个u8s,第一个到最低有效字节,第二个到最高有效字节?

DK.*_*DK. 11

明显,安全和便携的方式是使用数学.

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

如果你想要一个更高级别的界面,那byteorder就是设计用来做这个的箱子.

您应该绝对使用transmute转一[u8][u16],因为这并不能保证任何有关的字节顺序.

  • @Neikos上面的函数没有*来解释字节顺序,因为它不是以依赖它的方式编写的. (6认同)
  • @Neikos目标是将小端格式的u16数存储到字节数组中(注意函数的名称带有`le`后缀).这正是在这里发生的事情,无论你是在一台小型还是大型机器上.所以,它是便携式的. (5认同)

sel*_*tze 6

正如 DK 所建议的那样,您可能不应该真正使用unsafe代码来重新解释内存……但如果您愿意,可以这样做。

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

  • 你可能有对齐问题。如果您只是&mut [u8]从某处获取 a并将其转换为 a &mut [u16],则它可能指的是某些未正确对齐的内存区域以作为 a 进行访问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)
}
Run Code Online (Sandbox Code Playgroud)

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


She*_*ter 5

slice::align_to并且slice::align_to_mut从 Rust 1.30 开始稳定。这些函数处理sellibitze提出的对齐问题。

大端和小端的问题仍然是你需要担心的。您可以使用类似的方法u16::to_le来帮助解决这个问题。但是,我无法使用大端计算机进行测试。

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);
}
Run Code Online (Sandbox Code Playgroud)