【问题标题】:Order of evaluation: subexpressions, sequence points and postfix increments in C求值顺序:C 中的子表达式、序列点和后缀增量
【发布时间】:2018-05-30 15:16:50
【问题描述】:

围绕 C 语句 x = b[i] + i++; 及其定义展开了讨论。

所述语句未定义的论点如下:

C99 的第 6.5 条规定:

[...] 子表达式的求值顺序和副作用发生的顺序均未指定。

因此,不能保证i 在下标运算符中用作数组的索引后会自增。

但是,我对上述规范的解释不同。

C99 的第 6.5 节另外规定:

在上一个和下一个序列点之间,一个对象应该有它的存储值 通过表达式的评估最多修改一次。此外,先验值 应为只读以确定要存储的值。

C99 的第 5.1.2.3 条规定:

在 执行序列中的某些指定点称为序列点,所有副作用 之前的评估应该是完整的,并且没有后续评估的副作用 应该已经发生了。

附件 C 中给出了序列点列表,只有以下内容与有问题的陈述相匹配,恕我直言。

完整表达式的结尾

b[i]b 的元素i 的值)和i++(只是i)的评估可以在添加之前以任何顺序发生(以及= 的评估,这是RHS的值)完成。但是,整个语句的副作用被推迟到所有这些评估之后,因为这是唯一的序列点。在这种情况下,副作用是x 的变化和i 的增量。

谁是对的?是否有与论点相关的其他段落?在 C++ 中有什么不同吗?

【问题讨论】:

  • 未定义。副作用不会被推迟。它们保证发生在序列点之后,但不强制发生在之前。
  • 投反对票的人能否解释一下他/她的投票,以便我们改进问题?

标签: c undefined-behavior operator-precedence


【解决方案1】:

副作用不必推迟到序列点——它们可以在评估后立即应用。或不。

C 2011 有一些稍微不同(更精确)的语言:

如果标量对象上的副作用相对于不同的副作用是无序的 在同一标量对象或使用同一标量的值的值计算上 对象,行为未定义。

C 2011, §6.5 ¶2

i++i 有副作用,b[i] 在值计算中使用i,并且两个子表达式相对于彼此无序(即没有中间序列点)。因此,b[i] + i++ 的行为是未定义的。

【讨论】:

    【解决方案2】:

    您在第 6.5 节中的引用是相关的:

    在前一个序列点和下一个序列点之间,一个对象应该有它的 表达式的评估最多修改一次存储的值。 [在那种情况下,f]此外,先验值 应在[这些序列点之间]读取以确定值 存储起来。

    (我的澄清。)

    在您的声明中,i 的值被修改并用作b 的索引。您的语句不包含内部序列点,因此这些影响必须发生在同一对序列点之间。因此,该声明违反了引用的要求。然后适用第 4 节第 2 段:

    如果“应”或“不应”要求出现在 违反约束,行为未定义。 [...]

    仅此而已。无需考虑其他因素。您关于实际操作顺序的论点完全无关紧要。

    尽管如此,您声称

    整个语句的副作用被推迟到毕竟 这些评估是因为这是唯一的序列点。

    反映了对序列点的严重误解。序列点不代表事件发生的时间何时,而是表示事件发生之间的界限。副作用不仅不会延迟到下一个序列点,而且(按照标准)它们的约束远小于计算表达式值所涉及的操作。

    【讨论】:

      【解决方案3】:

      §6.5.2.4 状态

      更新操作数存储值的副作用应该发生在前一个序列点和下一个序列点之间。

      就像尤金的评论所建议的那样。如果这不够清楚,请参阅第 6.5 (1) 节中的问题中引用的陈述

      必须读取先验值以确定要存储的值。

      也被直接违反。 i 的值不仅是读取判断递增后的值,还可以作为下标运算符的操作数。

      这个questionits accepted answer 可能会提供额外的见解,因为它讨论了, 运算符引入的序列点及其与潜在的引起UB 的赋值行为的交互。

      【讨论】:

        猜你喜欢
        • 2010-12-17
        • 1970-01-01
        • 2015-12-21
        • 2017-08-04
        • 1970-01-01
        • 2013-04-03
        • 1970-01-01
        • 2016-07-12
        • 2021-04-24
        相关资源
        最近更新 更多