首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将字节转换为u64

将字节转换为u64
EN

Stack Overflow用户
提问于 2022-03-19 23:18:35
回答 1查看 628关注 0票数 1

我需要将Rust中字符串的前8个字节转换为一个u64,大端字节。此代码几乎有效:

代码语言:javascript
复制
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()要求源和目标都具有相同的长度。如果字符串太长,这很容易处理,因为我可以只获取一个适当长度的片段,但是如果字符串是短的,它就不能工作。

另一个问题是,这段代码是非常性能敏感的函数的一部分。它在一个大型数据集上运行在一个紧密的循环中。

在C中,我只需要对buf、memcpy对正确的字节数进行零化,然后对一个未签名的long进行强制转换。

有什么方法可以做到这一点在铁锈,因为它运行一样快?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-20 02:27:45

您只需修改现有代码,以便在复制时考虑到长度:

代码语言:javascript
复制
    let len = 8.min(s.len());
    buf[..len].copy_from_slice(&s.as_bytes()[..len]);

当然,如果字符串很短,这将把字节复制到u64中最重要的部分中。

至于性能:在这个简单的测试main()中,转换被完全优化成一个常量整数。因此,我们需要一个显式函数或循环:

代码语言:javascript
复制
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)
}

这个(在锈菌游乐场上)生成程序集:

代码语言:javascript
复制
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()。我们所看到的是,在编译的代码中没有分支,只有一个有条件的举动,大概是为了处理8len()的选择--以及无边界检查恐慌。

(当这个函数或代码片段内联到一个更大的循环中时,生成的程序集当然会有所不同--希望这样做会更好。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71542843

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档