【问题标题】:I can not understand some sentences in C99我看不懂C99中的一些句子
【发布时间】:2013-10-02 17:21:53
【问题描述】:

在 C99 6.5 中说:

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

“此外,应仅读取先验值以确定要存储的值”是什么意思?在 C99 中,为什么 a[i++] = 1 是未定义的行为?

【问题讨论】:

  • thisthisthis,甚至可能是this
  • @PascalCuoq,你可以把它变成一个答案。这可能是解释序列点的一个很好的例子。
  • @s.bandara 各种linked问题已经很详细地解释了。
  • 语言规范是编程语言的法律术语,它们也很有趣。也就是说,不是很多。
  • OP还特别询问,“此外,应仅读取先验值以确定要存储的值”可能是什么意思。

标签: c c99 language-lawyer


【解决方案1】:

a[i++] = 1 已定义(除非除了副作用的顺序之外还有其他未定义的原因:越界访问或未初始化的i)。

您的意思是a[i++] = i,这是未定义的行为,因为它在与i++ 相同的序列点之间读取i,这会改变它。

“此外,应仅读取先前值以确定要存储的值”部分表示允许i = i + 1;,尽管它从i读取并修改了i

另一方面,a[i] = (i=1); 是不允许的,因为尽管只向i 写入一次,但从i 读取的内容并不是为了计算要存储的值。

【讨论】:

    【解决方案2】:

    “应仅读取先验值以确定要存储的值”的措辞无疑是违反直觉的;为什么读取值的目的很重要?

    这句话的重点是要求哪些结果取决于哪些操作。

    我会从 Pascal's answer 那里窃取示例。

    这个:

    i = i + 1;
    

    完全没问题。 i 在同一个表达式中读取和写入,没有中间序列点,但没关系,因为直到读取完成后才能进行写入。在表达式 i + 1 及其子表达式 i 被完全计算之前,无法计算要存储的值。 (并且i + 1 没有可能延迟到写入之后的副作用。)这种依赖性强加了严格的顺序:必须在写入开始之前完成读取。

    另一方面,这个:

    a[i] = (i=1);
    

    具有未定义的行为。子表达式a[i]读取i的值,子表达式i=1写入i的值。但是写入存储在i 中的值不依赖于左侧读取i 的评估,因此没有定义读取和写入的顺序。 “要存储的值”是1;读取a[i] 中的i 并不能确定该值。

    我怀疑这种混淆是 ISO C 标准 2011 年修订版(以 N1570 的草案形式提供)重新措辞该部分的原因。标准还是有序列点的概念,但是6.5p2现在说:

    如果标量对象的副作用相对于其中任一对象而言是未排序的 对同一标量对象或值的不同副作用 使用相同标量对象的值进行计算,行为是 不明确的。如果有多个允许的排序 表达式的子表达式,如果这样的表达式的行为是未定义的 任何排序都会出现未排序的副作用。

    第 1 段明确说明了仅在 C99 中隐含的假设:

    运算符的操作数的值计算是有序的 在算子结果的值计算之前。

    第 5.1.2.3 节第 2 段解释了 sequenced beforesequenced after 关系。

    【讨论】:

    • 我对@9​​87654338@ 感到困惑是否意味着b = a++; 意味着a 的增量发生在a++ 评估为a 之前?
    • @ajay: 不。a++ 做了两件事:它计算一个值(比 a 的前一个值大 1),它具有修改 a 的副作用。副作用不是“价值计算”的一部分。赋值对b的修改只有在确定a++产生的值之后才能发生,但是赋值对b的修改和++a的修改可能发生在顺序(或并行)。
    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2017-07-19
    相关资源
    最近更新 更多