命令式编程中的一个序列点定义了计算机程序执行中的任何一点,在该点上保证了先前评估的所有副作用都已执行,并且尚未执行后续评估的副作用。
这是什么意思?有人可以用简单的语言解释一下吗?
答案 0 :(得分:38)
当序列点出现时,它基本上意味着您可以保证所有先前的操作都已完成。
在没有插入序列点的情况下更改变量两次是未定义行为的一个示例。
例如,i = i++;
未定义,因为i
的两次更改之间没有序列点。
请注意,这不仅仅是更改变量两次,这可能会导致问题。这实际上是任何其他用途的变化。在讨论事物的排序方式时,该标准使用术语“值计算和副作用”。例如,在表达式
a = i + i++
中,i
(值计算)和i++
(副作用)可以按任意顺序完成。
维基百科在C和C ++标准中有list of the sequence points,但最终列表应始终取自ISO标准。从C11附录C(释义):
以下是标准中描述的序列点:
&&
,||
和,
的第一个和第二个操作数的评估之间; ?:
运算符的第一个操作数以及第二个和第三个操作数中的任何一个; if
或switch
); while
或do语句的表达式; for
声明的每个表达式; 答案 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)
这意味着编译器可以进行时髦的优化,技巧和魔术,但必须在这些所谓的序列点达到明确定义的状态。