为什么XOR与整数交换会触发警告?

jpm*_*los 3 c bit-manipulation bitwise-operators undefined-behavior

我输入了以下程序:

#include <stdio.h>

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;
}
Run Code Online (Sandbox Code Playgroud)

没关系 当我尝试编译它时,我得到了这个:

$ 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
Run Code Online (Sandbox Code Playgroud)

这几乎是标准代码,不是吗?

为什么会触发警告?据我所知,int只要您使用C的标准实现,就会默认实现按位XOR .

非常感谢你.

Jul*_*ano 13

变量a在表达式中用作左值两次.

请记住,这x ^= y实际上是一个快捷方式x = x ^ y,它意味着第一个操作数被读取,然后被写入.

如果你从原始表达式中取出第一个操作,那很好,请参阅:

   b ^= a ^= b;    // OK
/*    2    1    */
Run Code Online (Sandbox Code Playgroud)

这里,a使用两次并b使用三次.由于赋值运算符是从右到左的关联,首先a ^= b计算,b只读取变量a,读取变量然后写入,并将结果(r1)传递给第二个操作.在第二动作中,b ^= r1,b被读出的第二时间(给予如前面读出的相同的值),然后写入.请注意,没有办法以不同的方式解释,没有未定义的行为.在上面的语句,a是只读一次,b读两次但都读返回相同的值,都ab被写入一次.没关系.

当你向左边添加第三个赋值时,它就成了一个问题:

   a ^= b ^= a ^= b;    // NOT OK
/*    3    2    1    */
Run Code Online (Sandbox Code Playgroud)

现在,a读取两次,一次操作1次,一次操作3次,也写入操作1和操作3. a操作3 应返回什么值,处理操作1后的原始值或值?

聪明的程序员可能认为操作1在处理操作3之前完全执行,但这不是由标准定义的.它恰好适用于大多数编译器.在操作3中,编译器可以很好地返回与a为操作1 返回的值相同的值,从而导致错误的结果.这是未定义的行为.


Pra*_*rav 9

a ^= b ^= a ^= b;调用未定义的行为.你应该用这个:

a ^= b;
b ^= a;
a ^= b;
Run Code Online (Sandbox Code Playgroud)