暂时将 [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);
}
我有一个 [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);
}