在C和C++中,“^=”运算符的区别是什么?

3
我想使用表达式交换由int *xint *y指向的值。
*x ^= *y ^= *x ^= *y;

(好的,我知道这个表达很别扭,我只是想知道它们之间的区别,没有冒犯的意思。)这在C++中可以运行,但在C中失败了。然而,如果我将其分为三个部分,如下所示:
*x ^= *y;
*y ^= *x;
*x ^= *y;

它可以适用于两种语言。

那么,在C和C++中,运算符^=有什么区别呢?


6
我在 "*x ^= *y ^= *x ^= *y;" 处停止阅读。如果您要提出问题,请呈现更少使人反感的代码。谢谢。 - Cheers and hth. - Alf
2
@Cheersandhth.-Alf,恐怕这个令人厌恶的代码行就是最终问题所在。 - Baum mit Augen
2
不确定为什么会有负评?该问题提供了可重现错误的工作代码。并不是很多提问者都这样做。它还揭示了CC ++之间一个有趣的差异,可能会影响其他人。我们现在真的因为代码势利而贬低吗? - Galik
1
你还应该考虑将你观察到的C和C++之间的实际区别,包括示例,再次添加到问题中。 - Baum mit Augen
2
这是C语言中的未定义行为,这就是问题所在。“为什么在C语言中无法正常工作?” - Raymond Chen
显示剩余10条评论
3个回答

10
区别并不在于您最初怀疑的指针,而是在于不同的评估顺序规则。在“新”的C++11中,“序列化之前规则”中,我们有:
内置赋值运算符和所有内置复合赋值运算符的副作用(修改左参数)在计算左右参数的值(但不是副作用)之后进行排序,并在赋值表达式的值计算之前进行排序(即,在返回对修改对象的引用之前)。
(来自cppr。)这个规则保证了你的表达式从右到左的求值顺序。
相比之下,C和C++98使用“序列点”。由于长语句中没有序列点,因此您有多个未排序的值修改指针所指向的值,从而引发未定义行为。
对于C,gcc会警告这一点(live)。对于C++98,它显然已经使用了新规则,这是可以的,因为未定义的行为是未定义的。
分割语句可以解决这个问题,因为语句的结尾明确地引入了需要的序列点。此外,这种方法更易读,并且不需要知道排序规则来确定代码是否正确。

供参考:在C++中,有关序列规则的很好的解释可以在这里找到。


很好地发现了,+1。但请注意,这只回答了当前的问题,而不是关于指针的原始问题。 - Cheers and hth. - Alf
如果您能提供更详细的关于“序列点”和“副作用”的标准注释,那么对于像我这样的初学者来说,阅读相关内容会更有帮助。这里有一个相关的帖子:未定义行为和序列点 - 吴俣铖
@吴俣铖 我认为对于这个答案来说,全面解释顺序并不在范围内,而我也不喜欢不完整的解释。因此,我将包括您评论中提供的链接作为参考。如果您找到C语言的好链接,请随意添加。 - Baum mit Augen

3

在单个语句中多次修改同一变量是未定义行为,因此当您执行 *x ^= *y ^= *x ^= *y 时,编译器可以执行任何操作。这也是为什么 ++i + i++ 等操作总是错误的原因。


1
一个侧面的注意事项 "++i + i++ 或类似的写法总是错的" 是虚假的。根据标准,这是未定义行为。 - sjsam
2
我的意思是它永远不是你打算做的事情。 我可以理解我被误解了。 - N. Shead
2
顺便提一下,"在一个语句中多次修改同一变量是未定义行为",这个说法在C和C++98中甚至不正确。++x, ++x; 是一个单独的语句,但并不属于未定义行为,因为逗号引入了一个序列点。 - Baum mit Augen

2
回答这个问题:在C和C++中,原始指针没有区别。
但我认为你真正想问的是其他问题...

1
因为这是唯一回答了原问题的答案,所以被点赞。 - Cheers and hth. - Alf
你的假设是正确的,起初我认为这是一个指针问题,但在阅读答案后,我发现它更可能与“求值顺序”有关,或者是一些称为“序列点”和“副作用”的东西,这些我知之甚少。 - 吴俣铖

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