在C/ c++中执行顺序是否总是相同的

Is the order of execution always the same in C/C++

本文关键字:是否 顺序 c++ 执行      更新时间:2023-10-16

这段代码总是产生相同的结果吗?

return c * (t /= d) * t * t + b;

所以我期望:

return ((c * (t / d) ^ 3) + b);

但我不确定编译器是否也可以解释为:

return ((c * t * t * (t / d)) + b)

我在C标准中搜索但找不到答案,我知道x = x++是未定义的,但在这里我不确定,因为t /= d周围的(),我认为迫使编译器首先计算该语句。

我在C标准中搜索过,但找不到答案

您要查找的是序列点

你的表达

c * (t /= d) * t * t + b

不包含任何序列点,因此子表达式可以按任何相对顺序求值。


注意这适用于C,因为您在问题中提到了这一点。您还标记了相关但非常不同的语言c++,它具有不同的规则。幸运的是,在这种情况下,它们给出了完全相同的结果。

2014-11-19工作草案PDF:N4296的相关文本为

1.9程序执行[introduction . Execution]

14与全表达式相关的每个值计算和副作用都在每个值之前排序与下一个要计算的完整表达式相关的计算和副作用。

15 除特别说明外,单个操作符和单个子表达式的操作数求值表达式是未排序的。[注意:在执行过程中计算不止一次的表达式中对于程序,不需要对其子表达式进行未排序和未确定排序的求值在不同的评估中表现一致。- end note] an的操作数的值计算在运算符结果的值计算之前对运算符进行排序。如果是标量的副作用对象相对于同一标量对象或值计算上的另一个副作用是无序的如果使用同一个标量对象的值,并且它们不是潜在并发的(1.10),则行为是并发的未定义的。[注:下一节对潜在并发性施加了类似但更复杂的限制。计算。

所以c++中的逻辑是,除非事情是显式排序的(例如,通过;分隔两个完整的表达式),然后它们可以以任何顺序发生。

正如(第二)突出显示的部分所提到的,当两个未排序的子表达式修改同一个对象(或者一个修改,一个读取)时,行为是未定义的。

上面的表达式,加上括号使运算顺序明确,如下:

return ((((c * (t /= d)) * t) * t) + b);
然而,这里的问题是,在这个表达式中没有序列点。因此,任何子表达式都可以以任意顺序对求值。

例如,编译器可以选择计算一次t的值,然后在它出现的每个地方使用原始值。相反,它可以先计算修改了tt /= d,然后在它出现的任何地方使用这个修改后的值。

简而言之,由于在没有序列点的单个表达式中读写变量,因此调用了未定义行为。

以下语句:

return c * (t /= d) * t * t + b;
在C中

调用未定义行为(我也相信c++)。这是因为t被求值了两次(包括(t /= d)子表达式),尽管有一个未排序的副作用(由复合赋值操作符产生),这影响了由t变量表示的对象。

当您遇到UB时,您应该停止考虑表达式的"适当"值。没有,因为任何事情都是可能的,包括关闭你的电脑。

最近版本的gccclang-Wall可能会告诉你表达式被怀疑调用UB。这里的警告是:

警告:'t'上的操作可能未定义[-Wsequence-point]

警告:未排序的修改和访问't' [- unsequenced]

相关文章: