为什么与整数进行异或交换会触发警告?

发布于 2024-10-19 13:55:55 字数 569 浏览 1 评论 0原文

我输入了以下程序:

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

就可以了。当我尝试编译它时,我得到了这样的信息:

$ 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 默认会实现按位异或。

非常感谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷你仙 2024-10-26 13:55:55

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

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

如果你把第一个操作从原来的表达式中取出来,就可以了,参见:

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

这里,a使用了两次,b使用了三次。由于赋值运算符是从右到左关联的,因此首先计算a ^= b,变量b仅被读取,变量a为读取然后写入,结果 (r1) 传递给第二个操作。在第二次操作中,b ^= r1b 被第二次读取(给出与先前读取的值相同的值),然后写入。请注意,没有办法进行不同的解释,没有未定义的行为。在上面的语句中,a仅读取一次,b读取两次,但两次读取返回相同的值,并且a>b 仅写入一次。没关系。

当您在左侧添加第三个赋值时,就会出现问题:

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

现在,a 被读取两次,一次在操作 1 上,一次在操作 3 上,并且还在操作 1 和操作 3 上写入。操作 3 中应该返回值,原始值还是操作 1 处理后的值?

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

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.

鸢与 2024-10-26 13:55:55

a ^= b ^= a ^= b; 调用 未定义行为< /a>.你应该使用这个:

a ^= b;
b ^= a;
a ^= b;

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

a ^= b;
b ^= a;
a ^= b;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文