首页 > 用异或交换两个变量值的疑惑

用异或交换两个变量值的疑惑

#include<stdio.h>
int main(){
    int a[2]={8,7};int min,i;
    i=0,min=1;
    a[min]^=a[i]^=a[min]^=a[i];//交换变量
//a[i]=a[i]^a[min],a[min]=a[i]^a[min],a[i]=a[i]^a[min];
    printf("%d %d ",a[i],a[min]);

}   

这个代码输出是7,0
交换变量一行换成下一行的注释句运行结果是7,8;
但是这两个不是等价的么,书上说是等价的;

#include<stdio.h>
int main(){
    int a,b;
    scanf("%d %d",&a,&b);
    a^=b^=a^=b;
    printf("%d %d",a,b);
}

而这里面的交换变量是成功的;
为什么呢?


gcc 4.2.1下 gcc -S生成的对应汇编代码:

7 in a[1] in -8(%rbp)

#8 in a[0] in -16(%rbp)
movq    (%rax), %rax
movq    %rax, -8(%rbp)
movq    L_main.a(%rip), %rax
movq    %rax, -16(%rbp)
#i in -24(%rbp) ;min in -20(%rbp) 
movl    $0, -24(%rbp)
movl    $1, -20(%rbp)
movslq  -24(%rbp), %rax
movl    -16(%rbp,%rax,4), %ecx
movslq  -20(%rbp), %rax
movl    -16(%rbp,%rax,4), %edx
#a[min] in %ecx ;a[i] in %edx
xorl    %ecx, %edx
movl    %edx, -16(%rbp,%rax,4)
#put it back in a[min]
movslq  -24(%rbp), %rax
#i=0 in %rax
movl    -16(%rbp,%rax,4), %ecx
#a[i] in %ecx
xorl    %edx, %ecx
#xorl a[i] with the result of a[min]^a[i]
movl    %ecx, -16(%rbp,%rax,4)
#put it back in a[i],now we put the original a[min] in a+i
movslq  -20(%rbp), %rax
#min=1 in %rax
movl    -16(%rbp,%rax,4), %edx
#a[min] in %edx,this a[min] differs from the origin,
#it is the result of the original a[i]^a[min]
xorl    %ecx, %edx
#original a[min] in %ecx and the original a[i]^a[min] in %edx
movl    %edx, -16(%rbp,%rax,4)
#put it back in a[min],now we put the original a[i] in a+min
movslq  -24(%rbp), %rax
movl    -16(%rbp,%rax,4), %esi
movslq  -20(%rbp), %rax
movl    -16(%rbp,%rax,4), %edx
#pass the parameters by registers,a+i in %esi,a+min in %edx

请把这本书扔掉

你可以看看微软的文档: C 序列点
你的代码行为是未定义的


我不知道那本书为什么这么说,但是我觉得大多数编译器都不是按照那本书来实现的。

a[min]^=a[i]^=a[min]^=a[i];

等于

a[min]^=(a[i]^=(a[min]^=a[i]));

等于

a[min] = a[min] ^ a[i]  ;
a[i]   = a[i]   ^ a[min];
a[min] = a[min] ^ a[i]  ;

代码没问题,输出确实是7 8 ,看看:
http://ideone.com/vmPSAw

是否问题出在代码之外的错误,比如编译的和运行的不是同一个版本之类的问题?


a[min]^=a[i]^=a[min]^=a[i]

这句跟一句话里面使用多个自增一样,是未定义行为。简而言之就是,你在一句代码里面多次访问了a[min],并做出了修改。第二次的访问使用了修改前的值还是修改后的值,不同编译器的实现不一样。

【热门文章】
【热门文章】