简体   繁体   English

c中的序列点

[英]sequence points in c

A sequence point in imperative programming defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.命令式编程中的序列点定义了计算机程序执行中的任何点,在该点上可以保证先前评估的所有副作用都已执行,并且后续评估的副作用尚未执行。

What does this mean?这是什么意思? Can somebody please explain it in simple words?有人可以用简单的话解释一下吗?

When a sequence point occurs, it basically means that you are guaranteed that all previous operations are complete.当一个序列点出现时,基本上意味着你可以保证之前的所有操作都完成了。

Changing a variable twice without an intervening sequence point is one example of undefined behaviour.在没有中间序列点的情况下更改变量两次是未定义行为的一个示例。

For example, i = i++;例如, i = i++; is undefined because there's no sequence point between the two changes to i .未定义,因为i的两次更改之间没有序列点。

Note that it's not just changing a variable twice that can cause a problem.请注意,不仅仅是两次更改变量会导致问题。 It's actually a change involved with any other use.这实际上是涉及任何其他用途的更改。 The standard uses the term "value computation and side effect" when discussing how things are sequenced.在讨论事物的排序方式时,该标准使用术语“值计算副作用”。 For example, in the expression a = i + i++ , the i (value computation) and i++ (side effect) may be done in arbitrary order.例如,在表达式a = i + i++i (值计算)和i++ (副作用)可以按任意顺序进行。

Wikipedia has a list of the sequence points in the C and C++ standards although the definitive list should always be taken from the ISO standard. Wikipedia 有 C 和 C++ 标准中的序列点列表,但最终列表应始终取自 ISO 标准。 From C11 appendix C (paraphrased):来自 C11 附录 C(释义):


The following are the sequence points described in the standard:以下是标准中描述的序列点:

  • Between the evaluations of the function designator and actual arguments in a function call and the actual call;在函数调用和实际调用中的函数指示符和实际参数的评估之间;
  • Between the evaluations of the first and second operands of the operators && , ||在运算符&&||的第一个和第二个操作数的计算之间, and , ; , 和, ;
  • Between the evaluations of the first operand of the conditional ?: operator and whichever of the second and third operands is evaluated;在条件?:运算符的第一个操作数的评估与第二个和第三个操作数中的任何一个评估之间;
  • The end of a full declarator;完整声明符的结束;
  • Between the evaluation of a full expression and the next full expression to be evaluated.在完整表达式的求值和要求值的下一个完整表达式之间。 The following are full expressions:以下是完整的表达:
    • an initializer;一个初始化程序;
    • the expression in an expression statement;表达式语句中的表达式;
    • the controlling expression of a selection statement ( if or switch );选择语句的控制表达式( ifswitch );
    • the controlling expression of a while or do statement; while或 do 语句的控制表达式;
    • each of the expressions of a for statement; for语句的每个表达式;
    • the expression in a return statement. return 语句中的表达式。
  • Immediately before a library function returns;在库函数返回之前;
  • After the actions associated with each formatted input/output function conversion specifier;在与每个格式化输入/输出函数转换说明符相关联的动作之后;
  • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call.在每次调用比较函数之前和之后,以及在对比较函数的任何调用和作为参数传递给该调用的对象的任何移动之间。

An important thing to note about sequence points is that they are not global, but rather should be regarded as a set of local constraints.关于序列点需要注意的重要一点是它们不是全局的,而是应该被视为一组局部约束。 For example, in the statement例如,在声明中

a = f1(x++) + f2(y++);

There is a sequence point between the evaluation of x++ and the call to f1, and another sequence point between the evaluation of y++ and the call to f2.在 x++ 的求值和对 f1 的调用之间有一个序列点,在 y++ 的求值和对 f2 的调用之间有另一个序列点。 There is, however, no guarantee as to whether x will be incremented before or after f2 is called, nor whether y will be incremented before or after x is called.但是,不能保证 x 是否会在调用 f2 之前或之后递增,也不能保证 y 是否会在调用 x 之前或之后递增。 If f1 changes y or f2 changes x, the results will be undefined (it would be legitimate for the compiler's generated code to eg read x and y, increment x, call f1, check y against the previously-read value, and--if it changed--go on a rampage seeking out and destroying all Barney videos and merchandise; I don't think any real compilers generate code that would actually do that, alas, but it would be permitted under the standard).如果 f1 更改 y 或 f2 更改 x,结果将是未定义的(编译器生成的代码可以合法地例如读取 x 和 y、增加 x、调用 f1、根据先前读取的值检查 y,以及--如果它改变了——继续横冲直撞,寻找并摧毁所有 Barney 视频和商品;我认为任何真正的编译器都不会生成真正能做到这一点的代码,唉,但在标准下是允许的)。

Expanding on paxdiablo's answer with an example.用一个例子扩展paxdiablo的答案。

Assume the statement假设语句

x = i++ * ++j;

There are three side effects: assigning the result of i * (j+1) to x, adding 1 to i, and adding 1 to j.有3个副作用:将i * (j+1)的结果赋值给x,给i加1,给j加1。 The order in which the side effects are applied is unspecified;应用副作用的顺序未指定; i and j may each be incremented immediately after being evaluated, or they may not be incremented until after both have been evaluated but before x has been assigned, or they may not be incremented until after x has been assigned. i 和 j 可以在被求值后立即增加,或者它们可能在两者都被求值后但在 x 被赋值之前不增加,或者它们可能在 x 被赋值之后才增加。

The sequence point is the point where all side effects have been applied (x, i, and j have all been updated), regardless of the order in which they were applied.序列点是所有副作用都已应用的点(x、i 和 j 都已更新),无论它们的应用顺序如何。

这意味着编译器可能会进行时髦的优化、技巧和魔法,但必须在这些所谓的序列点处达到明确定义的状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM