为什么v [i] = i ++在C中是未定义的行为?

时间:2013-07-03 21:29:26

标签: c undefined-behavior

阅读一篇关于ACCU重载的有趣文章#115:“恶魔可能会飞出你的鼻子”我发现作者说:

  在序列点之间

,不允许对涉及变量的状态做出任何假设。这也意味着在C语言中,与大多数其他语言不同,以下表达式会导致未定义的行为

     

v [i] = i ++;

     

因为赋值运算符不代表C

中的序列点

有人可以解释一下UB的详细推理是什么吗? 我认为在两个序列点之间对同一个变量进行多次写操作是个问题,除了v [i]别名的可能性之外我在这里看不到...

3 个答案:

答案 0 :(得分:5)

这不仅仅是写作。当您不知道是否正在读取变量的旧值或新值时,读取也会发挥作用。在这种情况下,无法说明v[i]是指i的旧值还是i的新值。

例如,表达式v[i] = i++可以解释为

  1. 执行作业:v[i] = i
  2. 增量i
  3. 或者,它可以解释为

    1. 获取ii_old = i
    2. 的旧值
    3. 增量i
    4. 执行作业:v[i] = i_old
    5. 您可以很容易地看到,代码的行为会根据其解释方式而改变。这些只是两种可能的不一致情况的例子。

      但该语言并未将行为限制在如此有限的各种场景中。相反,该语言表明行为是未定义的,这意味着,除其他外,编译器可以自由地拒绝以任何“可预测的”方式解释此代码。

答案 1 :(得分:3)

在同一序列点内有i的读取和写入。也就是说,i++在计算v[i]的地址之后可以在OR之前改变i。实际上,因为这种行为是未定义的,所以它们很可能都不会做这些事情 - 例如,编译器可以假定语句不可访问并将其删除。 (或者让恶魔飞出你的鼻子等等。)

答案 2 :(得分:3)

您已经纠正了在没有插入序列点的情况下多次修改变量会导致未定义的行为。但是还有一个额外的要求,即变量的值只能访问以确定要修改的值。这是不允许的第二个要求

v[i] = i++;

此处,i对数组索引的访问权限与对ii++)进行的修改无关。由于两次访问之间没有中间序列点,因此这是未定义的行为。