在C/ c++中执行顺序是否总是相同的
Is the order of execution always the same in 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
周围的()
,我认为迫使编译器首先计算该语句。
我在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
的值,然后在它出现的每个地方使用原始值。相反,它可以先计算修改了t
的t /= d
,然后在它出现的任何地方使用这个修改后的值。
简而言之,由于在没有序列点的单个表达式中读写变量,因此调用了未定义行为。
以下语句:
return c * (t /= d) * t * t + b;
在C中调用未定义行为(我也相信c++)。这是因为t
被求值了两次(包括(t /= d)
子表达式),尽管有一个未排序的副作用(由复合赋值操作符产生),这影响了由t
变量表示的对象。
当您遇到UB时,您应该停止考虑表达式的"适当"值。没有,因为任何事情都是可能的,包括关闭你的电脑。
最近版本的gcc
和clang
与-Wall
可能会告诉你表达式被怀疑调用UB。这里的警告是:
警告:'t'上的操作可能未定义[-Wsequence-point]
警告:未排序的修改和访问't' [- unsequenced]
- 检查 2 棵树是否具有相同的顺序
- 检查一个数组是否包含在另一个数组中,以相反的顺序,至少两次
- C++编译器是否优化了顺序静态变量读取?
- 同一互斥锁顺序上的锁定和解锁是否一致?
- C++评估顺序优化是否意味着对不同的操作数使用不同的内核?
- 标记为 std::memory_order_seq_cst 的单个原子操作是否会在所有位置触发顺序一致性?
- 如何检查参数包是否具有执行顺序中的确切类型
- 视觉C++:在 DLL 加载期间,全局变量初始化顺序是否具有确定性?
- c++标准是否指定了运算符&&(内置)的求值顺序?
- 顺序一致的原子负载(负载-负载对)是否形成线程间同步点
- 在C++中,是否可以在单个循环中顺序迭代多个迭代器
- 初始化值是否保证通过其自己的地址反映,而不考虑内存顺序
- 如果 RMW 操作没有任何变化,是否可以针对所有内存顺序对其进行优化
- 是否可以跨动态库控制销毁顺序?
- 验证(使用 static_assert)元组类型是否遵循某种顺序(有状态编译时检查)
- 委派的 ctor 是否受参数计算顺序的影响?
- 如何检查 2 个 c++ 数组在 O(1) 或 O(log n) 时间复杂度中是否相同(所有元素都相同,顺序很重要)?
- 是否有任何内置函数可以检查给定的两个数字在给定整数数组中的顺序是否相同?
- 编译器是否会简化按顺序执行多次的操作
- C++是否保证标准容器比较中操作数的顺序?