今天在看汇编的时候,突然想起变量交换的问题来,记得原来老郭跟我说过一种变量交换的方法——异或。也不知道是怎么会突然产生这种怨念,于是就上网查了一下,这种方式究竟好不好,结果是这种“技巧”除了糊弄面试官以外,基本上没有啥实用性……
void swap(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void swap2(int *a, int *b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
上面的swap就是“正常思维”的交换,下面的swap2就是“异或思维”的交换,本着不相信一切牛鬼蛇神的原则,我是一定要看到汇编代码才肯罢休的……
通过将C程序变为汇编程序以后(至少-O1优化),得到以下的汇编代码:
swap:
.LFB35:
.cfi_startproc
movl (%rdi), %eax
movl (%rsi), %edx
movl %edx, (%rdi)
movl %eax, (%rsi)
ret
.cfi_endproc
swap2:
.LFB36:
.cfi_startproc
movl (%rsi), %eax
xorl (%rdi), %eax
movl %eax, (%rdi)
xorl (%rsi), %eax
movl %eax, (%rsi)
xorl %eax, (%rdi)
ret
.cfi_endproc
即使看不懂汇编代码的同学至少也能看出来swap用了4行就解决了问题,而swap2用了6行才解决问题,并且在汇编的层面上,swap和swap2都没有使用“第三块内存”,虽然我们在swap中定义个了tmp变量,不过在优化的过程中,这个变量就被优化没了……
这样,swap2的所有优势都荡然无存了,不仅没有节省内存空间,而且运算的步骤也更长……
有兴趣的同学可以自己去看看不加任何编译优化是什么样的结果,其实即使不加任何编译优化,swap的汇编代码也比swap2要简洁的多……
#include <stdlib.h>
#include <stdio.h>
void print(int a, int b)
{
printf("%d, %d", a, b);
}
void swap(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void swap2(int *a, int *b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int main(int argc, char *argv[])
{
int a = 4;
int b = 5;
swap(&a, &b);
print(a, b);
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */
以上这段代码是为了懒惰的同学准备的,将上面代码直接生成汇编:gcc -S code.c -O2,然后看看code.s文件是怎样的……
本着自己动手丰衣足食的原则,有兴趣的同学应该使用自己的机器亲自验证一下,而不仅仅局限于别人的结论……