C / C ++中的执行顺序是否始终相同

时间:2016-06-26 22:54:16

标签: c++ c

此代码是否会产生相同的结果?

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,我认为强制编译器首先计算该语句。

3 个答案:

答案 0 :(得分:6)

  

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

您要搜索的内容是sequence point

你的表达

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

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

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

2014-11-19工作草案PDF:N4296的相关文字是

  

1.9程序执行[intro.execution]

     

...

     

14每个值之前,对与完整表达式相关的每个值计算和副作用进行排序   计算和副作用与下一个要评估的完整表达相关联。

     

15 除非另有说明,否则评估个体经营者的操作数和个体的子表达式   表达式没有排序。 [注意:在执行期间多次计算的表达式中   一个程序,对其子表达式的无序和不确定顺序的评估不一定​​是   在不同的评估中表现一致。 - 结束注释]的操作数的值计算   在运算符结果的值计算之前对运算符进行排序。如果对标量有副作用   对于相同标量对象的另一个副作用或值计算,对象未被排序   使用相同标量对象的值,它们不是潜在的并发(1.10),行为是   未定义即可。 [注意:下一节对潜在的并发性施加了类似但更复杂的限制   计算。 - 结束说明]

因此,C ++中的逻辑是,除非对事物进行明确排序(例如,通过;分隔两个完整的表达式),否则它们可以按任何顺序发生。

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

答案 1 :(得分:3)

以下声明:

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

在C中调用未定义的行为(我也相信C ++)。这是因为t被评估两次(计算(t /= d)子表达式),尽管副作用不明显(由复合赋值运算符产生),这会影响由t变量表示的对象。 / p>

你遇到UB的那一刻是你应该停止思考的那个"正确的"表达的价值。没有,因为一切皆有可能,包括关闭你的电脑。

最新版本的gccclang -Wall可能会告诉您表达式涉嫌调用UB。这里的警告是:

  

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

     

警告:无序修改和访问' [-Wunsequenced]

答案 2 :(得分:3)

上面的表达式,括号使操作顺序显式,如下:

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

然而,这里的问题是此表达式中没有sequence point。因此,可以按任何顺序评估任何子表达式

例如,编译器可以选择评估t的值一次,然后使用它出现的每个位置的原始值。相反,它可能会首先评估修改t /= d的{​​{1}},然后在其出现的任何其他位置使用此修改后的值。

简而言之,因为您在没有序列点的单个表达式中读取和写入变量,所以您调用undefined behavior