为什么XOR与整数交换会触发警告?
我输入了以下程序:
#include int main(void) { int a = 3; int b = 42; printf("a = %d\nb = %d\n", a, b); printf("Exchanging values.\n"); a ^= b ^= a ^= b; printf("a = %d\nb = %d\n", a, b); return 0; }
没关系。 当我尝试编译它时,我得到了这个:
$ gcc test.c -o test -Wall -Wextra -ansi -pedantic-errors test.c: In function 'main': test.c:11: warning: operation on 'a' may be undefined
这几乎是标准代码,不是吗?
为什么会触发警告? 据我所知,只要您使用C的标准实现,就会默认为int
实现按位XOR。
非常感谢你。
变量a
在表达式中用作左值两次。
请记住, x ^= y
实际上是x = x ^ y
的快捷方式,这意味着读取第一个操作数,然后写入。
如果你从原始表达式中取出第一个操作,那很好,请参阅:
b ^= a ^= b; // OK /* 2 1 */
这里, a
使用两次, b
使用三次。 由于赋值运算符是从右到左的关联,首先计算a ^= b
,仅读取变量b
,读取变量a
然后写入,并将结果( r1 )传递给第二个操作。 在第二个操作中,第二次读取b ^= r1
, b
(给出与先前读取的值相同的值),然后写入。 请注意,没有办法以不同的方式解释,没有未定义的行为。 在上面的语句中, a
只读取一次, b
读取两次但两次读取都返回相同的值, a
和b
只写入一次。 没关系。
当你向左添加第三个赋值时,它就成了一个问题:
a ^= b ^= a ^= b; // NOT OK /* 3 2 1 */
现在, a
被读取两次,一次是在操作1上,一次是在操作3上,也是在操作1和操作3上写入的。操作3,原始值或操作1之后的值应该返回什么值?
聪明的程序员可能认为操作1在处理操作3之前完全执行,但这不是由标准定义的。 它恰好适用于大多数编译器。 在操作3中,编译器可以很好地返回与为操作1返回的a
相同的值,从而导致错误的结果。 这是未定义的行为。
a ^= b ^= a ^= b;
调用未定义的行为 。 你应该用这个:
a ^= b; b ^= a; a ^= b;