![](/img/trans.png)
[英]Convert a generic type (u16, u32, u64) into a vector of bytes Vec<u8> in Rust
[英]Convert bytes to u64
我需要将 Rust 中字符串的前 8 个字节转换为 u64,大端。 这段代码几乎可以工作:
fn main() {
let s = String::from("01234567");
let mut buf = [0u8; 8];
buf.copy_from_slice(s.as_bytes());
let num = u64::from_be_bytes(buf);
println!("{:X}", num);
}
此代码存在多个问题。 首先,它仅在字符串恰好为 8 个字节长时才有效。 .copy_from_slice()
要求源和目标的长度相同。 如果 String 太长,这很容易处理,因为我可以只抓取一段合适的长度,但如果 String 很短,那就不行了。
另一个问题是这段代码是 function 的一部分,它对性能非常敏感。 它在大型数据集上紧密循环运行。
在 C 中,我只是将 buf、memcpy 归零到正确的字节数,然后转换为无符号长整型。
有没有办法在 Rust 中执行此操作,运行速度一样快?
您可以只修改现有代码以在复制时考虑长度:
let len = 8.min(s.len());
buf[..len].copy_from_slice(&s.as_bytes()[..len]);
如果字符串很短,这当然会将字节复制到将成为u64
的最高有效位的位置。
至于性能:在这个简单的测试main()
中,转换被完全优化为常量 integer。因此,我们需要一个明确的 function 或循环:
pub fn convert(s: &str) -> u64 {
let mut buf = [0u8; 8];
let len = 8.min(s.len());
buf[..len].copy_from_slice(&s.as_bytes()[..len]);
u64::from_be_bytes(buf)
}
这(在 Rust 游乐场上)生成程序集:
playground::convert:
pushq %rax
movq %rdi, %rax
movq $0, (%rsp)
cmpq $8, %rsi
movl $8, %edx
cmovbq %rsi, %rdx
movq %rsp, %rdi
movq %rax, %rsi
callq *memcpy@GOTPCREL(%rip)
movq (%rsp), %rax
bswapq %rax
popq %rcx
retq
我有点怀疑与仅发出复制字节的指令相比, memcpy
调用实际上是一个好主意,但我不是指令级性能方面的专家,并且大概它至少等于您的 C 代码显式调用memcpy()
。 我们确实看到编译后的代码中没有分支,只有一个条件移动,大概是为了处理8
vs. len()
选择——并且没有边界检查恐慌。
(当这个 function 或代码片段被内联到一个更大的循环中时,生成的程序集当然会有所不同——希望更好。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.