c中的序列点

Posted

技术标签:

【中文标题】c中的序列点【英文标题】:sequence points in c 【发布时间】:2011-04-04 06:31:33 【问题描述】:

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

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

【问题讨论】:

Sequence points and partial order 的可能重复项 【参考方案1】:

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

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

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

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

***在 C 和 C++ 标准中有一个list of the sequence points,尽管最终列表应始终取自 ISO 标准。来自 C11 附录 C(释义):


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

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

【讨论】:

我期待您提供更多信息 pax。我对 c 有基本的了解。您对我之前的问题给出了很好的解释。 修改变量的值并以任何方式使用该值也是未定义的行为,而不是在没有干预序列点的情况下确定要存储的值。例如,a[i++] = i 是未定义的,因为尽管它只修改了 i 的值一次,但 i 的值用于确定存储到 i 中的值之外的其他目的。 知道这如何与 OOE 结合,或者是另一个抽象层次吗? @Matt:这是一个抽象层。只要你写了正确的C代码,不管你的平台是否OOE,结果都是一样的。事实上,即使你编写了错误的代码,你也应该得到相同的结果,因为每种情况下的二进制可执行文件都是相同的。 @Matt Joiner 我们需要添加警告:从执行线程的上下文的角度到上面的出色答案。 OOE 通常对指令流是不可见的——CPU 的指令调度程序已确保满足指令之间的数据依赖关系。当涉及到内存和缓存时,情况就完全不同了,如果内存看到的完成顺序很重要,C 和 C++ 标准都非常明确需要使用内存屏障。【参考方案2】:

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

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

在 x++ 的求值和对 f1 的调用之间有一个序列点,在 y++ 的求值和对 f2 的调用之间有另一个序列点。但是,不能保证 x 是否会在调用 f2 之前或之后递增,也不保证 y 是否会在调用 x 之前或之后递增。如果 f1 更改 y 或 f2 更改 x,则结果将是未定义的(编译器生成的代码可以合法地读取 x 和 y、递增 x、调用 f1、检查 y 与先前读取的值以及--如果它发生了变化——疯狂地寻找并销毁所有 Barney 视频和商品;我不认为任何真正的编译器生成的代码会真正做到这一点,唉,但标准允许这样做)。

【讨论】:

如果任何函数修改了 x 或 y,那么这将在序列点之后完成(函数实际调用之前的那个)。行为未指定。【参考方案3】:

以示例扩展 paxdiablo 的答案。

假设语句

x = i++ * ++j;

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

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

【讨论】:

但是,我们应该指出x = i++ * ++j 的结果是明确定义的,不像paxdiablo 的i = i++ 示例...【参考方案4】:

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

【讨论】:

以上是关于c中的序列点的主要内容,如果未能解决你的问题,请参考以下文章

recharts img 未在自定义点中呈现

输入字段字符序列

为啥是 ”\?” C/C++ 中的转义序列?

Three.js 多边形三角剖分在伪重复点中失败

使用 2d/3dsplines 从一组嘈杂的数据点中查找曲率? (C++)

c中的序列点