首页 文章

在组装方面可以想到“让”和其他Rust成语吗?

提问于
浏览
1

使用C语言编写时,可以直接推断编译后的分配方式 . 我知道Rust是一种使用功能特性的高级语言,但由于它被称为“系统语言”,我想知道在Rust中是否可行 .

例如,我想循环遍历整数数组并计算3个相邻数字的最大乘积:

unsigned int a[10] = {4, 2, 3, 8, 1, 0, 7, 4, 9, 2};
unsigned int i, p=1, max=0;
for(i=0; i<8; i++, p=1) {
    p = a[i] * a[i+1] * a[i+2];
    if(p>max) max = p;
}

等效的Rust代码可能看起来像这样(不确定这是否是惯用的方式):

let a = [4, 2, 3, 8, 1, 0, 7, 4, 9, 2];
let mut max = 0;
for i in 0..8 {
    let p = a[i] * a[i + 1] * a[i + 2];
    if p > max {
        max = p;
    }
}

在C中, p 是在循环之前定义的变量,每次都被赋予一个新值;另一方面,在Rust中, let p 在循环中使用,这在程序方面难以思考 .

C更接近汇编代码吗?或者也可以对Rust进行推理吗?

1 回答

  • 3

    TL; DR:完全可以在汇编方面对Rust代码进行推理 . 但是,您需要熟悉C提供的安全功能和高级抽象 .


    如果你想在汇编方面考虑C和Rust,首先要考虑的是你使用哪个C编译器?

    GCC和Clang / LLVM发出了截然不同的组件 . 虽然GCC生成的程序集是pretty close to the C code,但Clang / LLVM似乎是unroll the loop in the original example . (这打开了一个问题:"which is closer to assembly - C or C?")

    Rust也使用LLVM,所以让我们将其与Clang进行比较 . 这是Clang组件的一部分:

    imul esi, eax
      mov edx, dword ptr [rdi + 20]
      imul esi, edx
      cmp esi, ecx
      cmovbe esi, ecx
    

    我不是汇编专家,但这应该是展开循环的一次迭代 . 可以访问索引数组,乘法和替换当前最大值的检查 .

    Rust assembly的相应片段如下所示:

    cmp r8, 5
      je .LBB0_16
      imul eax, edx
      mov esi, dword ptr [rdi + 20]
      imul eax, esi
      cmp eax, ecx
      cmovbe eax, ecx
    

    唯一的区别是一些寄存器的使用方式不同,并且在开头就有一个比较和条件跳转 . 这是Rust在索引到 a 时执行的边界检查 . 你没有在C中 - 如果数组太小,任何事情都可能发生 . 在Rust中你会得到一个明显的恐慌,但它的成本很低(运行时检查=更多说明) .

    如果这是额外的成本是一个问题,有一个逃避舱口:不安全的代码 .

    p = unsafe {*a.as_ptr().offset(i) * *a.as_ptr().offset(i+1) * *a.as_ptr().offset(i+2)};
    

    有了这个改变,我们get assembly大部分类似于C组件,但我们失去了Rust的安全性的一部分 .


    所有这一切,并没有真正的装配相当于Rust的 let x = 或C的 int x = . 这些成语是更高层次的抽象,正在说"I want to have a new local variable" . 由编译器决定如何制作它 . 它可以使用内存位置或可用的寄存器,以较合适的方式,但CPU不关心变量 .

相关问题