swap:不使用中间变量,交换两个a、b两个变量


“写一个swap函数,要求不使用中间变量,交换a、b两个变量的值”,应该算是老生常谈了。但今天却碰到一点新问题。

今天阅读《程序员的自我修养--链接、装载与库》,P98有一小段示例代码:

void swap(int *a, int *b){
        *a ^= *b ^= *a ^= *b;
}

我觉得用一行代码来实现交换a与b的值,还是很简洁的。于是顺手发给了一个朋友。结果朋友说,这个函数的执行出现了问题。

// File: swap.c
#includ <stdio.h> void swap(int *a, int *b){ *a ^= *b ^= *a ^= *b; } int main(void){ int a = 5, b = 10; swap(&a, &b); printf("a: %d, b: %d\n", a, b); }

预期的输出应为 a: 10, b:5,使用VC 2010编译,输出符合预期。但使用gcc 4.2.4 (Ubuntu 8.04, 32位),默认参数编译gcc swap.c,其执行结果确是:

a: 0, b: 5

a的输出是错误的。那就gcc -S swap.c,查看一下它的汇编代码吧,swap函数的代码如下:

.globl swap
        .type   swap, @function
swap:
" 记*a的值为va,*b的值为vb
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ebx
        movl    8(%ebp), %eax     
        movl    (%eax), %ebx    " ebx 存放 va
        movl    12(%ebp), %eax
        movl    (%eax), %ecx    " ecx 存放 vb
        movl    8(%ebp), %eax
        movl    (%eax), %edx    " edx 存放 va
        movl    12(%ebp), %eax
        movl    (%eax), %eax    " eax 存放 vb
        xorl    %eax, %edx        " edx = (va ^= vb)
        movl    8(%ebp), %eax
        movl    %edx, (%eax)    " *a =  (va ^= vb)
        movl    8(%ebp), %eax
        movl    (%eax), %eax    " eax = (va ^= vb)
        movl    %ecx, %edx      " edx = vb
        xorl    %eax, %edx      " edx = va
        movl    12(%ebp), %eax
        movl    %edx, (%eax)    " *b = va
        movl    12(%ebp), %eax
 movl (%eax), %eax " eax = va movl %ebx, %edx " edx = va xorl %eax, %edx " edx = 0
        movl    8(%ebp), %eax    " 
        movl    %edx, (%eax)
        popl    %ebx
        popl    %ebp
        ret

纯红色的三行代码,导致a的输出是0,估计是gcc对*a ^= *b ^= *a ^= *b的处理有问题。但奇怪的是,如果开启优化选项进行编译,得出的结果反而是对的,使用gcc -O2 swap.c,执行的结果就是对的,经过查看,其O2情况下汇编代码是正确的。

有人知道这是不是gcc的一个bug?还是我哪里弄错了?请不吝指教。

这不是gcc的bug,详见@garbageMan提供的链接。

 

下面附赠两个不使用中间变量的swap函数吧:

// 将*a ^= *b ^= *a ^= *b拆开写
// 利用 a ^ a ^ b == b
void swap(int *a, int *b){
    *a ^= *b;
    *b ^= *a;
    *a ^= *b;
}

// 利用 a + b - b = a
void swap(int *a, int *b){
    *a = *a + *b;
    *b = *a -  *b;
    *a = *a -  *b;
}

 

下面是K&R C语言中的swap函数:

// interchange *px and *py
void swap(int *px, int *py){
    int temp;

    temp = *px;
    *px = *py;
    *py = temp;
}

 

祝好。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM