什么可以确保后缀的副作用在计算+之后发生?
没有这样的保证。后缀的副作用可能发生在+
的值计算之前或之后。
相对于使用相同的i
的加法运算符的值计算,后置运算符对i
的副作用没有顺序。
否,加法运算符的值计算使用其操作数的值计算结果。 +
的操作数是i++
(不是i
)和1
。正如您在问题中所涵盖的,i
的读取是在i++
的值计算之前进行排序的,因此(传递性)在{{1 }}。
保证按以下顺序发生以下事情:
- 读取
+
。
-
i
的值计算(操作数:步骤1的结果)
-
++
的值计算(操作步骤2和+
的结果)
1
的副作用必须在第1步之后发生,但可能会达到该限制。
,
i++ + 1
并非由于使用后缀运算符而未定义,因为它仅对一个对象产生一种副作用,并且该对象的值仅在该位置引用。 i++
表达式明确产生i
的先验值,并且该值是加到1的值,而不管i
实际何时更新。
(我们不知道i++ + 1
的定义是否正确,因为由于各种其他原因,事情可能出错:i
未初始化或不确定或无效,或者出现数字溢出或指针溢出犯)。
如果在同一评估阶段中我们尝试两次修改同一对象i++ + i++
,则会发生未定义的行为。这可以用指针进行卷积,因为(*p)++ + (*q)++
仅在p
和q
指向同一位置时才递增同一对象;否则很好。
如果在同一评估阶段中,我们尝试观察在表达式中其他地方(例如i++ + i
)修改的对象的值,则也会发生未定义的行为。 +
的右侧访问i
,但是在左侧i++
的副作用方面没有顺序; +
运算符不施加序列点。不用说,在i++ + 1
中,1
不会尝试访问i
。
,
在评估i++ + 1
时会发生以下情况:
- 计算子表达式
i++
。它产生i
的先前值。
- 评估
i++
还具有增加i
的存储值的副作用-但请注意,未使用该增加的值。
- 对子表达式
1
进行评估,得出明显的值。
- 对
+
运算符求值,得出i++
的结果加上1
的结果。只有在确定了左右子表达式的值之后,这种情况才会发生(但可以在副作用发生之前或之后持续发生)。
仅保证++
运算符的副作用在下一个序列点之前的某个时间发生。 (这就是C99的术语。C11标准以不同的方式提出了相同的规则。)但是由于表达式中的其他内容均不取决于该副作用,因此它何时出现并不重要。没有冲突,所以没有未定义的行为。
在i++ + i
中,根据副作用是否发生,在RHS上对i
的评估将产生不同的结果。而且由于顺序是不确定的,因此标准举手表示行为是不确定的。但是在i++ + i
中,不会发生此问题。
,
“什么可以确保后缀的副作用在计算+之后发生?”
没有什么可以保证的。您必须像使用i
的原始值一样进行操作,并且在某些时候它需要执行副作用,但是只要一切运行正常,编译器如何实现这一点就无关紧要或以什么顺序。它可以(并且在某些情况下可以)将其实现为大致等同于以下任何一种情况:
auto tmp = i;
i = tmp + 1; // Could be done here,or after the next expression,doesn't matter since i isn't read again
tmp + 1; // produces actual value of i++ + 1
或
auto tmp = i + 1;
i = tmp; // Could be done here,doesn't matter since tmp isn't changed again
(tmp - 1) + 1; // produces actual value of i++ + 1
or(对于具有足够信息的原语或内联运算符重载)将表达式优化为:
++i; // Usually the same as i++ + 1 if compiler has enough knowledge
因为后缀增量后加一个可以被视为前缀增量,而后不加一。
要点是,由编译器来确保副作用有时发生,这可能在计算+
之前或之后;编译器只需要确保已存储或可以恢复i
的原始值即可。
这里的各种扭曲似乎毫无意义(显然,++i
是最好的选择,否则,i + 1;
后跟++i
最简单),但是它们通常是必要的在给定架构上使用硬件原子;如果该架构提供了fetch_then_add
指令,则您希望将其实现为:
auto tmp = fetch_then_add(i,1); // Returns original value of i,while atomically adding 1
tmp + 1;
但是,如果它仅提供add_then_fetch
指令,则您需要:
auto tmp = add_then_fetch(i,1); // Returns incremented value of i
(tmp - 1) + 1;
与许多事情一样,C ++标准没有强加优先顺序,因为实际的硬件并不总是协同工作。如果能够完成工作并按文档所述运行,则使用什么顺序都没有关系。
本文链接:https://www.f2er.com/3113291.html