我一直在阅读有关在不使用临时变量的情况下交换变量内容的问题,除了着名的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机器的值而不使用临时变量,那么这段代码是有效还是完全废话?谢谢你。
答案 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输出,然后查看
以了解更多有关有效组装的原理。