繁体   English   中英

c中的序列点

[英]sequence points in c

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

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

当一个序列点出现时,基本上意味着你可以保证之前的所有操作都完成了。

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

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

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

Wikipedia 有 C 和 C++ 标准中的序列点列表,但最终列表应始终取自 ISO 标准。 来自 C11 附录 C(释义):


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

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

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

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.

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