使用异或运算符交换变量的值

4
这是在C++和C#中交换值的有效方法。
X ^= Y;
Y ^= X;
X ^= Y;

这是在C++中交换值的有效方法。

X ^= Y ^= X ^= Y;

但是为什么在C#中这个不起作用呢?

2
什么没有起作用?你怎么使用它? - Matteo Umili
1
我认为如果你给出一个例子,你会得到更多的关注。就我个人而言,我对为什么单独的表达式有效感兴趣,但是堆叠的表达式却无效。 - juharr
1
@rcgldr 我也有同样的想法,但是这个 x ^= (y ^= (x ^= y)); 也不“管用”。实际上,赋值运算符是从右到左的(https://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx),我不知道它们怎么可能是其他方式。 - juharr
2
第二种方法不是在C++中交换值(或执行其他任何操作)的有效方式。这是未定义的行为。 - Benjamin Lindley
除了“它是否有效”,它是“在现实生活中完全无用的有趣派对技巧”。像这样编写的代码比temp = x; x = y; y = temp;解决方案慢得多[预计2-3倍或更差,因为值的立即依赖性] [该解决方案也适用于浮点、双精度、指针、对象、结构等等,而不仅仅是整数类型]。 - Mats Petersson
显示剩余10条评论
3个回答

1
int X = 3;
X = X + X++; // X = 6;

int X = 3
X = X++ + X; // X = 7;

同样地:
int X = 3;
int Y = 5;
X = (Y ^= X ^= Y)^X; // X = 5

然而:
int X = 3;
int Y = 5;
X = X^(Y ^= X ^= Y); // X = 0

不幸的是:

X = X^(Y ^= X ^= Y)X ^= Y ^= X ^= Y 的一个等价式


0

我检查了编译器生成的 MSIL。在第一种情况下,一切正常 - push x,push y,xor,pop x 等等。 在第二种情况下,它以 push x,push y,push x,push y 开始,并最终在最后一个 xor 中使用 x 的初始值:

ldloc.0
ldloc.1
ldloc.0
ldloc.1
xor
dup
stloc.0
xor
dup
stloc.1
xor
dup
stloc.0

0

我尝试生成C++代码的汇编并反编译.NET代码,以下是我得到的结果:

汇编

mov eax, DWORD PTR _X$[ebp]
mov ecx, DWORD PTR _Y$[ebp]
mov edx, DWORD PTR [eax]
xor edx, DWORD PTR [ecx]
mov eax, DWORD PTR _X$[ebp]
mov DWORD PTR [eax], edx
mov ecx, DWORD PTR _Y$[ebp]
mov edx, DWORD PTR _X$[ebp]
mov eax, DWORD PTR [ecx]
xor eax, DWORD PTR [edx]
mov ecx, DWORD PTR _Y$[ebp]
mov DWORD PTR [ecx], eax
mov edx, DWORD PTR _X$[ebp]
mov eax, DWORD PTR _Y$[ebp]
mov ecx, DWORD PTR [edx]
xor ecx, DWORD PTR [eax]
mov edx, DWORD PTR _X$[ebp]
mov DWORD PTR [edx], ecx

从我对汇编的一点了解来看,我认为这基本上是:

X ^= Y;
Y ^= X;
X ^= Y;

C#(使用JetBrains dotPeek生成)

int& local1 = @X;
int num1 = ^local1;
int& local2 = @Y;
int num2 = ^local2;
int num3 = X ^= Y;
int num4;
int num5 = num4 = num2 ^ num3;
^local2 = num4;
int num6 = num5;
int num7 = num1 ^ num6;
^local1 = num7;

我不确定 &,^,@ 的含义,但我认为基本上是:

int xStartingValue = X;
X ^= Y;
Y ^= X;
X = xStartingValue ^ Y;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接