Why does XOR swap with integers trigger a warning?

2020-02-14 07:08发布

I typed the following program:

#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;
}

and it's ok. When I try to compile it, I get this:

$ 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

That's pretty much standard code, isn't it?

Why does it trigger a warning? As far as I know, bitwise XOR is implemented by default for int as long as you are using a standard implementation of C.

Thank you very much.

2条回答
劳资没心,怎么记你
2楼-- · 2020-02-14 07:16

a ^= b ^= a ^= b; invokes Undefined Behaviour. You should use this:

a ^= b;
b ^= a;
a ^= b;
查看更多
你好瞎i
3楼-- · 2020-02-14 07:33

Variable a is used as an lvalue twice in the expression.

Keep in mind that x ^= y is in fact a shortcut for x = x ^ y, and it means that the first operand is read, then written.

If you take the first operation out from the original expression, it is fine, see:

   b ^= a ^= b;    // OK
/*    2    1    */

Here, a is used twice and b is used three times. Since the assignment operator is right-to-left associative, first a ^= b is calculated, variable b is only read, variable a is read and then written, and the result (r1) is passed to the second operation. On the second operation, b ^= r1, b is read a second time (giving the same value as read previously) and then written. Note there is no way to interpret differently, no undefined behavior. In the above statement, a is read only once, b is read twice but both reads return the same value, and both a and b is written only once. It is ok.

When you add the third assignment to the left, it becomes a problem:

   a ^= b ^= a ^= b;    // NOT OK
/*    3    2    1    */

Now, a is read twice, once on operation 1 and once on operation 3, and also written on operation 1 and operation 3. What value should a return on operation 3, the original value or the value after operation 1 is processed?

The clever programmer may think that operation 1 is completely executed before operation 3 is processed, but this is not defined by the standard. It just happens to work with most compilers. On operation 3, the compiler may very well return the same value for a as it is returned for operation 1, causing the wrong result. This is undefined behavior.

查看更多
登录 后发表回答