序列点在c

时间:2010-08-26 13:10:39

标签: c sequence-points

  

命令式编程中的一个序列点定义了计算机程序执行中的任何一点,在该点上保证了先前评估的所有副作用都已执行,并且尚未执行后续评估的副作用。

这是什么意思?有人可以用简单的语言解释一下吗?

4 个答案:

答案 0 :(得分:38)

当序列点出现时,它基本上意味着您可以保证所有先前的操作都已完成。

在没有插入序列点的情况下更改变量两次是未定义行为的一个示例。

例如,i = i++;未定义,因为i的两次更改之间没有序列点。

  

请注意,这不仅仅是更改变量两次,这可能会导致问题。这实际上是任何其他用途的变化。在讨论事物的排序方式时,该标准使用术语“值计算副作用”。例如,在表达式a = i + i++中,i(值计算)和i++(副作用)可以按任意顺序完成。

维基百科在C和C ++标准中有list of the sequence points,但最终列表应始终取自ISO标准。从C11附录C(释义):


以下是标准中描述的序列点:

  • 在函数调用和函数调用中的实际参数的评估与实际调用之间;
  • 在运算符&&||,的第一个和第二个操作数的评估之间;
  • 评估条件?:运算符的第一个操作数以及第二个和第三个操作数中的任何一个;
  • 完整声明者的结尾;
  • 在评估完整表达式和下一个要评估的完整表达式之间。以下是完整表达式:
    • 初始化程序;
    • 表达式语句中的表达式;
    • 选择语句的控制表达式(ifswitch);
    • 控制while或do语句的表达式;
    • for声明的每个表达式;
    • 表达式在return语句中。
  • 紧接库函数返回之前;
  • 与每个格式化输入/输出函数转换说明符关联的操作之后;
  • 在每次调用比较函数之前和之后,以及对比较函数的任何调用和作为参数传递给该调用的对象的任何移动之间。

答案 1 :(得分:10)

关于序列点的一个重要注意事项是它们不是全局的,而应该被视为一组局部约束。例如,在声明中

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

在评估x ++和调用f1之间有一个序列点,在y ++的评估和对f2的调用之间有另一个序列点。但是,不能保证在调用f2之前或之后x是否会递增,也不能保证y在调用x之前或之后是否递增。如果f1改变y或f2改变x,则结果将是未定义的(编译器生成的代码例如读取x和y,递增x,调用f1,检查y与先前读取的值,以及 - 如果它改变了 - 继续横冲直撞寻找并销毁所有Barney视频和商品;我认为任何真正的编译器都不会产生真正能够做到这一点的代码,唉,但是根据标准允许这样做。

答案 2 :(得分:3)

以一个例子扩展paxdiablo的答案。

假设声明

x = i++ * ++j;

有三种副作用:将i * (j+1)的结果分配给x,将i加1,并将1加1。副作用的应用顺序是未指定的; i和j可以在被评估之后立即递增,或者它们可以不被递增,直到已经评估了两个之后但是在分配了x之前,或者它们可以不递增直到分配了x之后。

序列点是已应用所有副作用的点(x,i和j都已更新),无论它们的应用顺序如何。

答案 3 :(得分:1)

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