[英]sequence points in c
命令式编程中的序列点定义了计算机程序执行中的任何点,在该点上可以保证先前评估的所有副作用都已执行,并且后续评估的副作用尚未执行。
这是什么意思? 有人可以用简单的话解释一下吗?
当一个序列点出现时,基本上意味着你可以保证之前的所有操作都完成了。
在没有中间序列点的情况下更改变量两次是未定义行为的一个示例。
例如, i = i++;
未定义,因为i
的两次更改之间没有序列点。
请注意,不仅仅是两次更改变量会导致问题。 这实际上是涉及任何其他用途的更改。 在讨论事物的排序方式时,该标准使用术语“值计算和副作用”。 例如,在表达式
a = i + i++
,i
(值计算)和i++
(副作用)可以按任意顺序进行。
Wikipedia 有 C 和 C++ 标准中的序列点列表,但最终列表应始终取自 ISO 标准。 来自 C11 附录 C(释义):
以下是标准中描述的序列点:
&&
、 ||
的第一个和第二个操作数的计算之间 , 和,
;?:
运算符的第一个操作数的评估与第二个和第三个操作数中的任何一个评估之间;if
或switch
);while
或 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;
有3个副作用:将i * (j+1)
的结果赋值给x,给i加1,给j加1。 应用副作用的顺序未指定; i 和 j 可以在被求值后立即增加,或者它们可能在两者都被求值后但在 x 被赋值之前不增加,或者它们可能在 x 被赋值之后才增加。
序列点是所有副作用都已应用的点(x、i 和 j 都已更新),无论它们的应用顺序如何。
这意味着编译器可能会进行时髦的优化、技巧和魔法,但必须在这些所谓的序列点处达到明确定义的状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.