命令式编程中的顺序点定义了计算机程序执行中的任何点,在该点处,可以保证先前评估的所有副作用都已执行,并且尚未执行后续评估的副作用。
这是什么意思?有人可以用简单的话解释一下吗?
命令式编程中的顺序点定义了计算机程序执行中的任何点,在该点处,可以保证先前评估的所有副作用都已执行,并且尚未执行后续评估的副作用。
这是什么意思?有人可以用简单的话解释一下吗?
当一个序列点出现时,基本上意味着你保证之前的所有操作都完成了。
在没有中间序列点的情况下更改变量两次是未定义行为的一个示例。
例如,i = i++;
未定义,因为对 . 的两次更改之间没有序列点i
。
请注意,不仅仅是两次更改变量会导致问题。这实际上是涉及任何其他用途的更改。在讨论事物如何排序时,该标准使用术语“价值计算和副作用”。例如,在表达式
a = i + i++
中,i
(值计算)和i++
(副作用)可以以任意顺序进行。
维基百科有一个C 和 C++ 标准中的序列点列表,尽管最终列表应始终取自 ISO 标准。来自 C11 附录 C(释义):
以下是标准中描述的序列点:
&&
在运算符、||
和,
;的第一个和第二个操作数的计算之间?:
运算符的第一个操作数的计算与第二个和第三个操作数中的任何一个计算之间;if
或switch
)的控制表达式;while
or do 语句的控制表达式;for
;关于序列点需要注意的重要一点是它们不是全局的,而是应该被视为一组局部约束。例如,在声明中
a = f1(x++) + f2(y++);
在 x++ 的计算和对 f1 的调用之间有一个序列点,在 y++ 的计算和对 f2 的调用之间有另一个序列点。但是,不能保证 x 是否会在调用 f2 之前或之后递增,也不保证 y 是否会在调用 x 之前或之后递增。如果 f1 更改 y 或 f2 更改 x,则结果将是未定义的(编译器生成的代码可以合法地读取 x 和 y、递增 x、调用 f1、检查 y 与先前读取的值以及--如果它发生了变化——疯狂地寻找并销毁所有 Barney 视频和商品;我不认为任何真正的编译器生成的代码会真正做到这一点,唉,但在标准下它是允许的)。
用一个例子扩展paxdiablo的答案。
假设声明
x = i++ * ++j;
有三个副作用:将结果赋值i * (j+1)
给 x,将 1 加到 i,以及将 1 加到 j。应用副作用的顺序未指定;i 和 j 可以在被评估后立即递增,或者在两者都被评估之后但在分配 x 之前它们可能不会递增,或者在分配 x 之后它们可能不会递增。
序列点是应用了所有副作用的点(x、i 和 j 都已更新),无论它们应用的顺序如何。
这意味着编译器可能会进行时髦的优化、技巧和魔术,但必须在这些所谓的序列点处达到明确定义的状态。