这个表达式 a = a + b - ( b = a );由于C++中的序列点而给出错误的输出

Does this expression a = a + b - ( b = a ); gives wrong output because of sequence point in C++?

本文关键字:输出 出错 错误 由于 表达式 C++      更新时间:2023-10-16

参考这个问题。

我已经多次尝试了相同的程序,并且我看到其他人(一群朋友)使用相同的逻辑进行交换,但他们都没有找到错误的输出。我想问一下,由于序列点,是否有可能获得错误的输出。

C++11 不再有序列点,但是是的,该行是未定义的行为,因为b的修改不是相对于其读取进行排序的。

这意味着任何事情都可能发生;不过,一般来说,主要问题是编译器可能会对事件的确切顺序重新排序。

是的,据我所知,这是未定义的行为。此处的分号是唯一的序列点,因此未定义赋值是在使用相同的变量之前还是之后发生的。

现在,如果你的所有朋友都使用相同的编译器和相同的平台,这似乎很有可能,他们都会看到相同的结果,使用相同的编译器,所以这并不奇怪。这就是这部分问题的答案。

基本上是的。它可能会给出错误的结果,因为在这一行中,B 既是写入的,也是读取的,并且没有指定首先会发生什么。

很可能你已经尝试过很多次了,但你使用相同的编译器,对吧?在这种情况下,您不太可能观察到不同的结果。对于给定的相同代码位,编译器通常会产生稳定的相同结果。

要看到差异,您可能需要更改编译器,或者至少更改一些选项,例如或多或少的激进优化。

这个表达式的问题在于,从理论上讲,它可以编译为:

assign b  <- a
a = a + b - a     // but now, B is already equal a

assign temp1 <- a
assign temp2 <- b
assign b  <- a
a = temp1 + temp2 - a   // here values are preserved

是的,这是未定义的行为它会给出以下警告

$ g++ -Wall -o test test.cpp test.cpp: 在函数 'int main()' 中: test.cpp:11:21: 警告:"b"上的操作可能未定义 [-W序列点]

如果你使用上面的"技巧"而不是标准的swap,使用Visual Studio,你会有一个不愉快的惊喜。评估的副作用仍然存在。

C 标准(1999 年版)在第 6.5 节第 2 条中说:

在上一个和下一个序列点之间,对象应通过表达式的计算最多修改一次其存储值。此外,应仅读取先前的值以确定要存储的值。

所以,是的,此代码违反了序列点规则(从中读取b但不确定b的新值)。C++从 C 继承了这一点。