使用指针和"^="交换值

3

我尝试使用 ^= 交换值(我知道最好使用另一个变量来完成这个操作),但结果不正确。

#include <stdio.h>

int main() {
    int a = 3, b = 5, *pa = &a, **ppa = &pa, *pb = &b, **ppb = &pb;
    *pa ^= *pb;
    *pb ^= *pa;
    *pa ^= *pb;
    printf("pointer 1: a = %d, b = %d\n", a, b);
    a ^= b ^= a ^= b;
    printf("variables: a = %d, b = %d\n", a, b);
    *pa ^= *pb ^= *pa ^= *pb;
    printf("pointer 2: a = %d, b = %d\n", a, b);
    return 0;
}

结果如下:

这是结果

pointer 1: a = 5, b = 3
variables: a = 3, b = 5
pointer 2: a = 0, b = 3

我想知道为什么*pa ^= *pb ^= *pa ^= *pb不能正常工作。有人能告诉我吗?
3个回答

7

在这个表达式中,赋值操作之间没有序列点:

*pa ^= *pb ^= *pa ^= *pb;

因此,行为未定义。

在下面的赋值语句中也没有序列点:

a ^= b ^= a ^= b;

所以,那行代码的行为也是未定义的。如果它能够正常工作,那么你是幸运或者不幸的。


2
@MOHAMED,你的观点是什么?未定义行为就是这样:未定义。可能有效;也可能无效。不要将其与基于证据的行为混淆,因为它本质上就存在缺陷。 - WhozCraig
因此,您必须在答案中提到,即使在第一种情况下它起作用,这意味着始终是未定义的行为。 - MOHAMED
@MOHAMED OK,我已经完成了。我原来的评论是在暗示我的陈述是不正确的吗? - David Heffernan

3
你需要一个中间序列点。否则,这是未定义的行为。

1
在回答您的问题之前,我想介绍一下:

序列点:

序列点是指在某个时间点上,所有已经发生的副作用都已经完成。

标准规定:

在前一个序列点和下一个序列点之间,一个对象通过表达式的求值最多只能被修改一次其存储值。此外,先前的值只能被访问以确定要存储的值。

现在,您的问题是,在表达式中:

a ^= b ^= a ^= b;  

并且

 *pa ^= *pb ^= *pa ^= *pb;  

只有一个序列点; (在表达式的结尾处),你在第一个表达式中两次修改了a,并且在两个序列点之间(先前的;和这里的表达式末尾的;)在第二个表达式中修改了*pa,导致程序行为未定义

进一步阅读:comp.lang.c FAQ list · 问题3.8


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接