#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]
,并做出了修改。第二次的访问使用了修改前的值还是修改后的值,不同编译器的实现不一样。