我最近发现了一种不使用第三个变量就可以交换两个变量值的方法。
a^=b^=a^=b
但是当我在不同的编译器上尝试上述代码时,我得到了不同的结果,有些正确,有些不正确。
这段代码有什么严重的问题吗?
我最近发现了一种不使用第三个变量就可以交换两个变量值的方法。
a^=b^=a^=b
但是当我在不同的编译器上尝试上述代码时,我得到了不同的结果,有些正确,有些不正确。
这段代码有什么严重的问题吗?
这段代码有什么严重的问题吗?
有!
a^=b^=a^=b
实际上会在C和C++中引发未定义的行为,因为您尝试在两个序列点之间多次更改 a
的值。
尝试编写以下代码(虽然并不完全可靠)
a ^= b;
b ^= a;
a ^= b;
使用b ^= a ^= b ^= a
来交换两个变量的值。
P.S: 永远不要尝试在不使用第三个变量的情况下交换两个变量的值。始终使用第三个变量。
编辑:
正如@caf所指出的那样,b^=a^=b
是可以的,即使^=
运算符的参数计算顺序未指定,由于表达式中对b
的所有访问都用于计算存储在b
中的最终值,因此行为是良好定义的。
b
的修改实际上是可以的,因为它只是读取来确定新值(b ^= a ^= b;
也是可以的)。 - caf=
运算符的参数计算顺序是未指定的。 - Prasoon Saurava = b
不会按顺序计算相对于b的值。无论 b
是否包含对 a
自身的已排序副作用都没有关系。它们必须相对于 a = b
左操作数的值计算进行排序才能有效。 - Johannes Schaub - litbb ^= a ^= b;
的定义和 i = a[i];
一样,原因是它们都是定义有意义的。虽然 b
和 (a ^= b)
的求值顺序未指定,但在计算新值之前,两者都必须被求值。 - caf如果你正在使用C ++,为什么不使用STL中的swap算法?它非常适合这个目的,并且很清楚它的作用:
#include <algorithm>
using namespace std;
// ...
int x=5, y=10; // x:5 y:10
swap(x,y); // x:10 y:5
我建议你在c++中使用std::swap()。
对于c语言,使用这个宏。注意,你需要先比较a和b,否则当它们指向同一内存位置时,你会擦除该值并将其变为0。
#define swap(a, b) ((a) == (b) || (a) ^= (b), (b) ^= (a), (a) ^= (b))
a == b
时,你如何计算最终结果为 0
?最初,a = b = X
。执行 a ^= b
后,a == 0
。执行 b ^= a
后,b == X
。最后,执行 a ^= b
,则 a == X && b == X
。这正是我们所期望的。 - Phil Miller基于 R. & sellibitze 的贡献:
使用逗号运算符:
(a^=b,b^=a,a^=b);
来自文本和维基百科:
逗号运算符可用于将相关表达式链接在一起。逗号链接的表达式列表从左到右进行评估,最右侧表达式的值是组合表达式的值。它充当一个序列点。
序列点保证了所有先前评估的副作用都已经执行,并且尚未执行后续评估的任何副作用。它消除了原始表达式执行顺序不明确而产生的未定义行为。
a = a ^ (a ^= b, b ^= a);
,而 ^
运算符的左侧可能在括号内表达式之前或之后被计算。 - R.. GitHub STOP HELPING ICEa ^= b
被完全评估,然后是b ^= a
,然后是a ^= b
。由于所有这些都是明确定义的,使用逗号运算符将它们串在一起也是明确定义的。当然,这并不适用于分隔函数参数的类似逗号。 - David Thornley按照以下方式进行:
a ^= b;
b ^= a;
a ^= b;
这个怎么样?
a = a + b;
b = a - b;
a = a - b;
a=a*b;
b=a/b;
a=a/b;
我想知道为什么没有人建议给表达式加括号。看起来这不再是未定义行为了。
a^=(b^=(a^=b));