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