【发布时间】:2013-07-18 21:49:48
【问题描述】:
可能重复:
Potential Problem in “Swapping values of two variables without using a third variable”
我最近在一个社区中读到,我们可以使用 XOR 技巧轻松交换两个数字,而无需使用第三个。
m^=n^=m^=n;提到了技巧。
你们怎么看?这个技巧总是有用的吗?
【问题讨论】:
可能重复:
Potential Problem in “Swapping values of two variables without using a third variable”
我最近在一个社区中读到,我们可以使用 XOR 技巧轻松交换两个数字,而无需使用第三个。
m^=n^=m^=n;提到了技巧。
你们怎么看?这个技巧总是有用的吗?
【问题讨论】:
你写它的方式,它是未定义的行为。这是因为您在同一序列点中多次修改变量。但是,如果您将其重写如下:
m ^= n;
n ^= m;
m ^= n;
那么就安全了。然而,“有用”是另一个问题,它很少“有用”,有时它实际上比实际使用临时要慢!
您还需要注意别名(指针/引用),因为如果您尝试与自身交换某些内容,那么您最终会意外地将您的值归零。例如:
#define SWAP(m, n) { m ^= n; n ^= m; m ^= n; }
int x[] = { 1, 2, 3, 4 };
int i = 0;
int j = 0;
SWAP(x[i], x[j]); // whoops, x[0] == 0 now, not 1!
更传统的交换实现没有这个问题。
【讨论】:
不,它在 C 和 C++ 中都是未定义的行为。它有时可能会起作用,但您不应该依赖它。
即使是“固定”的变体也并不总是有效:
m ^= n;
n ^= m;
m ^= n;
如果 m 和 n 是对同一个变量的引用,这将失败。在这种情况下,它将值设置为零。
C 没有引用,但即使在 C 中,如果你尝试使用这个技巧,仍然会潜伏着危险:
您可以尝试将技巧扩展为交换数组中的两个值,但如果您使用相同的索引,这同样会失败:
a[m] ^= a[n];
a[n] ^= a[m];
a[m] ^= a[n];
现在如果 m == n 再次设置 a[m] 的值为零。
请不要使用这样的“聪明”技巧。使用临时变量交换两个值。
【讨论】:
使用这个技巧,您可以节省一个额外的内存位置来保存一个临时值。 它可能对整数很有效,但是可读吗?您的上一代优化器可能会这样做。
【讨论】:
int temp = x; x = y; y = temp;,后两者。
y 不会在两条指令之间添加依赖关系吗?因此,由于写入后读取而没有配对。这同样适用于前 2 条指令,除非我遗漏了什么:)
mov x, y; 是一个错字。应该是mov x reg1;。
这通常更危险(在您的情况下,它实际上是未定义的行为;加上如果一个数字为零,就会出错)。除非您的内存非常低,否则最好只使用临时变量(或 stl 交换函数)。这更清楚您在做什么,也更易于维护。
【讨论】: