如何将两个u8原语转换为u16原语?

Hyd*_*n14 4 rust

我正在使用Vec<u8>缓冲区将二进制文件读入Rust程序.流中的两个字节代表一个big-endian u16.

到目前为止,我已经想出如何转换为原语的唯一方法是先将u16两个元素转换为Strings,看起来很糟糕.

码:

let vector: Vec<u8> = [1, 16].to_vec();
let vector0: String = format!("{:02x}", vector[0]);
let vector1: String = format!("{:02x}", vector[1]);
let mut vector_combined = String::new();
vector_combined = vector_combined + &vector0.clone();
vector_combined = vector_combined + &vector1.clone();
let number: u16 = u16::from_str_radix(&vector_combined.to_string(), 16).unwrap();

println!("vector[0]: 0x{:02x}", vector[0]);
println!("vector[1]: 0x{:02x}", vector[1]);
println!("number: 0x{:04x}", number);
Run Code Online (Sandbox Code Playgroud)

输出:

vector[0]: 0x01
vector[1]: 0x10
number: 0x0110
Run Code Online (Sandbox Code Playgroud)

She*_*ter 16

如果你实际上有两个不同的u8s,传统的解决方案涉及按位操作,特别是移位和按位OR.这需要零堆分配并且非常有效:

let number = ((vector[0] as u16) << 8) | vector[1] as u16;
Run Code Online (Sandbox Code Playgroud)

并有图解说明:

             A0                   B0
        +--------+           +--------+
        |XXXXXXXX|           |YYYYYYYY|
        +-------++           +-------++
                |                    |
 A1 = A0 as u16 |     B1 = B0 as u16 |
+---------------v+   +---------------v+
|00000000XXXXXXXX|   |00000000YYYYYYYY|
+---------------++   +---------------++
                |                    |
   A2 = A1 << 8 |                    |
+---------------v+                   |
|XXXXXXXX00000000|                   |
+---------------++                   |
                |              +--+  |
                +-------------->OR<--+
                               +-++
                                 |
                     V = A2 | B1 |
                 +----------+----v+
                 |XXXXXXXXYYYYYYYY|
                 +----------------+
Run Code Online (Sandbox Code Playgroud)

但是,你真的在​​狭隘地看待你的问题.你没有两个u8,你有一个&[u8].

在这种情况下,使用byteorder crate:

extern crate byteorder;

use byteorder::{ByteOrder, LittleEndian};

fn main() {
    let data = [1, 16];
    let v = LittleEndian::read_u16(&data);
    println!("{}", v);
}
Run Code Online (Sandbox Code Playgroud)

当您想要通过缓冲区处理读取时,这显示了它的强大功能:

extern crate byteorder;

use byteorder::{BigEndian, LittleEndian, ReadBytesExt};

fn main() {
    let data = [1, 16, 1, 2];
    let mut current = &data[..];

    let v1 = current.read_u16::<LittleEndian>();
    let v2 = current.read_u16::<BigEndian>();

    println!("{:?}, {:?}", v1, v2); // Ok(4097), Ok(258)
}
Run Code Online (Sandbox Code Playgroud)

如您所见,您需要意识到输入数据的字节顺序.

也可以看看:


您原始帖子的免费代码审核:

  • 没有必要在to_vec这里使用,vec!而是使用.

  • 没有必要指定绝大多数类型.

let vector = [1u8, 16].to_vec();

let vector0 = format!("{:02x}", vector[0]);
let vector1 = format!("{:02x}", vector[1]);
let mut vector_combined = String::new();
vector_combined = vector_combined + &vector0.clone();
vector_combined = vector_combined + &vector1.clone();
let number = u16::from_str_radix(&vector_combined.to_string(), 16).unwrap();
Run Code Online (Sandbox Code Playgroud)
  • 添加时,在引用字符串之前无需克隆字符串.
  • 有没有必要转换String到另一个... Stringfrom_str_radix.
let vector0 = format!("{:02x}", vector[0]);
let vector1 = format!("{:02x}", vector[1]);
let mut vector_combined = String::new();
vector_combined = vector_combined + &vector0;
vector_combined = vector_combined + &vector1;
let number = u16::from_str_radix(&vector_combined, 16).unwrap();
Run Code Online (Sandbox Code Playgroud)
  • 没有必要创建一个空String来追加,只需使用vector0
let vector0 = format!("{:02x}", vector[0]);
let vector1 = format!("{:02x}", vector[1]);
let vector_combined = vector0 + &vector1;
let number = u16::from_str_radix(&vector_combined, 16).unwrap();
Run Code Online (Sandbox Code Playgroud)
  • 根本不需要创建两个字符串,一个将执行:
let vector_combined = format!("{:02x}{:02x}", vector[0], vector[1]);
let number = u16::from_str_radix(&vector_combined, 16).unwrap();
Run Code Online (Sandbox Code Playgroud)

当然,这仍然不是正确的解决方案,但它更好.

  • 您可能需要更新此答案以使用现在存在的 `u16::from_le_bytes()` 或 `u16::from_be_bytes()` 函数。请参阅 https://doc.rust-lang.org/std/primitive.u16.html#method.from_be_bytes (2认同)
  • @youR.Fate 提到过,但这对于 OP 来说不是一个很好的解决方案,因为他们没有可以开始的数组。这意味着他们必须处理错误情况,然后执行转换。byteorder 一步即可完成此操作。 (2认同)

vir*_*tor 5

您可以将第一个元素相乘以将其移动到更高的字节,然后添加第二个元素。它只需要额外的铸造:

let a: u8 = 1;
let b: u8 = 2;
let c: u16 = (a as u16 * 256) + b as u16;
println!("c: {}", c); // c: 258
Run Code Online (Sandbox Code Playgroud)

  • 我的意思是,不一定是为了优化目的,而是为了清楚起见。位移位似乎更清楚地解释了您在做什么:“我想向左移动 8 位,然后将另一个数字放在空的右半部分以创建一个数字”。乘法做同样的事情,但对于阅读代码的人来说,这似乎是解析的另一个步骤。 (6认同)
  • 我不知道关于二进制操作的 *ton*,但是左移不是比乘法更合适吗? (3认同)

归档时间:

查看次数:

1906 次

最近记录:

7 年,4 月 前