阅读有关 ACCU 过载 #115 的有趣文章:“恶魔可能从你的鼻子飞出”,我发现作者说:
在序列点之间,您不得对所涉及变量的状态做出任何假设。这也意味着在 C 中,与大多数其他语言不同,以下表达式会导致未定义的行为
v[i] = i++;
因为赋值运算符不代表 C 中的序列点
有人可以解释这里暗示 UB 的详细推理是什么吗?我认为这将是在两个序列点之间对同一个变量进行多次写入的问题,除了 v[i] 别名 i...
阅读有关 ACCU 过载 #115 的有趣文章:“恶魔可能从你的鼻子飞出”,我发现作者说:
在序列点之间,您不得对所涉及变量的状态做出任何假设。这也意味着在 C 中,与大多数其他语言不同,以下表达式会导致未定义的行为
v[i] = i++;
因为赋值运算符不代表 C 中的序列点
有人可以解释这里暗示 UB 的详细推理是什么吗?我认为这将是在两个序列点之间对同一个变量进行多次写入的问题,除了 v[i] 别名 i...
这不仅仅是关于写入。当您不知道您是在读取变量的旧值还是新值时,读取也会发挥作用。在这种情况下,无法确定v[i]
是指的是 的旧值i
还是 的新值i
。
例如,表达式v[i] = i++
可以解释为
v[i] = i
i
或者,或者,它可以解释为
i
:i_old = i
i
v[i] = i_old
如您所见,代码的行为会根据其解释方式而变化。这些只是两种可能的不一致情况的示例。
但是该语言并不将行为限制在如此有限的各种场景中。相反,语言说行为是未定义的,这意味着编译器可以自由地拒绝以任何“可预测的”方式解释此代码。
i
在同一个序列点内有一个读和一个写。也就是说,i++
可以在计算 的地址之前或之后改变 i v[i]
。事实上,由于这种行为是未定义的,它很可能不会做这两件事——例如,编译器可以假定该语句不可访问并将其删除。(或者让恶魔从你的鼻子里飞出来等等)
您是正确的,在没有干预序列点的情况下多次修改变量会导致未定义的行为。但是还有一个额外的要求,即仅访问变量的值以确定要修改的值。这是不允许的第二个要求
v[i] = i++;
这里对数组索引的 ' 值的访问与对( )i
的修改无关。由于两次访问之间没有中间序列点,因此这是未定义的行为。i
i++