使用寄存器交换值

时间:2014-09-14 21:36:06

标签: c++ c assembly

我一直在阅读有关在不使用临时变量的情况下交换变量内容的问题,除了着名的xor算法之外,我还发现了x86上汇编的XCHG指令。所以我写了这段代码:

void swap(int *left, int *right){
__asm__ __volatile__(
        "movl %0, %%eax;"
        "movl %1, %%ebx;"
        :
        : "r" (*left), "r" (*right)
    );
__asm__ __volatile__(
        "xchg %eax, %ebx;"
            );
__asm__ __volatile__(
        "movl %%eax, %0;"
        "movl %%ebx, %1;"
        : "=r" (*left), "=r" (*right)
    );}

它确实有效但后来我意识到XCHG指令根本就没有必要。

void swap(int *left, int *right){
__asm__ __volatile__(
        "movl %0, %%eax;"
        "movl %1, %%ebx;"
        :
        : "r" (*left), "r" (*right)
    );
__asm__ __volatile__(
        "movl %%ebx, %0;"
        "movl %%eax, %1;"
        : "=r" (*left), "=r" (*right)
    );}

第二个函数也可以,但似乎没有人提到使用寄存器交换变量,所以这段代码被认为是错误的,实际上它并没有真正正常工作?我错过了什么吗?

我意识到这只适用于x86,但由于大多数人拥有intel x86处理器,这个代码可以用于任何现实世界的编程吗?我意识到这可能不会比使用临时变量的常规交换更快,但我从理论的角度来问。如果在测试或面试期间有人要求我在C中编写一个函数来交换x86机器的值而不使用临时变量,那么这段代码是有效还是完全废话?谢谢你。

3 个答案:

答案 0 :(得分:5)

有效,是的。 根据我的标准,你是一个没有雇用的人。

为什么呢?成本。

std :: swap可以很好地完成工作,并且可能足够快。 您的代码将具有更高的维护成本。

由于性能原因,肯定有时候会进入汇编程序 这不是其中之一。

答案 1 :(得分:1)

首先,您的内联汇编在很多方面都被打破了:

  • 滥用volatile,这并不代表你想要的东西。
  • 你不要告诉编译器你破坏寄存器。 (这可以修复)
  • 编译器可以在内联汇编块
  • 之间插入代码

对于程序员和编译器来说,内联汇编很难做到正确。

此外,内联汇编可能会在非常小心的情况下进行优化,但它会影响编译器,从而影响优化器的能力(寄存器分配,重新排序等),这通常会导致整体性能下降。我不反对内联汇编(或编译器内在函数),但它需要非常小心的处理,这使得它在大多数情况下都不合理。

答案 2 :(得分:0)

std::swap将编译为比此更有效的汇编。

该代码比编译器发出的代码慢,而且损坏。

它在不告知编译器的情况下掩盖了EAX和EBX,尤其是在启用优化的情况下进行编译,很容易失败,但是即使没有优化也不安全。

请参见How to write a short block of inline gnu extended assembly to swap the values of two integer variables?,以获取有关xchg的正确 asm的示例,以及一种更好的版本,该版本仅使用约束条件以零个asm指令交换C变量,由编译器自行确定它要在哪个寄存器中注册哪个C变量。asm("" : "=r" (a), "=r" (b) : "1" (a), "0" (b));


即使您使用带有0条asm语句且正好相反的输入/输出约束的内联asm进行此操作,也仍然会破坏常量传播和范围分析,从而使优化失败。 https://gcc.gnu.org/wiki/DontUseInlineAsm我对that answer I linked earlier所做的编辑包括纯C交换,显示了恒定传播在那里起作用,但内联-asm交换都不起作用。

因此,即使是正确编写的版本,也不能用于任何实际用途,只是作为练习/示例,为GNU C内联汇编使用输入/输出约束,以避免一开始mov / end到实际的asm块,并尽可能多地交给编译器。


只有当您做某事时,汇编程序才能取得比您个人更好的表现,Asm才能赢得性能。 (C++ code for testing the Collatz conjecture faster than hand-written assembly - why?

查看正常功能(How to remove "noise" from GCC/clang assembly output?)的编译器的asm输出,然后查看

以了解更多有关有效组装的原理。