提问者:小点点

不是a[i ] = 1(一)其中,增量的计算相对于数组的索引是无序的,导致违反S6.5.2


题长字数限制..

正如@Karl Knectel所指出的,我很困惑,相对于I增量操作,获取数组索引的操作不是按顺序的吗?如果它们是未排序的,为什么C标准6.5.2一行提到“”(我理解的单词/短语中添加了强调,适用于此处)

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

我读了这个问题,我无法理解C99中的一些句子,其中OP试图理解为什么a[i]=1是未定义的。接受和Pascal Cuoq投票最高的答案之一提到这是定义的行为。

我还尝试使用< code>-std=c99、< code>-Wall和< code>-Wextra标志以及一系列其他标志(基本上是GCC 11.2.0中启用的所有标志)来编译程序,但是代码没有抛出任何警告。

然而,我的问题/困惑是为什么这是一个定义的行为?

来自C11标准S6.5.2

如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是未排序的,则行为是未定义的。如果一个表达式的子表达式有多种允许的排序,如果这种未排序的副作用出现在任何一种排序中,那么行为就是未定义的。

在阅读了SO上的大多数线程(带有标签[C][序列点])后,我的理解/推理是i会导致更新i的值的副作用。在这种情况下,这种副作用对使用相同缩放器对象的值计算没有排序。我知道一个[整数对象]构成了值计算。那么,它应该是未定义的行为?

即使从C99 S6.5(p2)

此外,应只读先验值以确定要存储的值。

我理解这个表达式也应该使< code>a[i ] = 1未定义?


共2个答案

匿名用户

在这种情况下,使用相同的缩放器对象,该副作用不会被排序到值计算中。

i中涉及的标量对象是i。更新i的副作用与i值的计算无关,因为C 2018 6.5.2.4(规定后缀递增和递减运算符的行为)第2段规定:

…结果的值计算在产生更新操作数存储值的副作用之前排序…

C 2011 的措辞相同。(C 2018 仅包含对 C 2011 的技术更正和澄清。

即使从C99 S6.5(p2)

此外,应只读先验值以确定要存储的值。

C 1999 标准中的规则不适用于 2011 或 2018 标准;它必须单独解释。在1999年至2011年间,该标准从孤立的序列点转向关于测序关系的更精细的规则。

i 中,读取先验值以确定 i 的新值应该是什么,因此它符合该规则。

该规则试图说明对标量对象的任何读取都必须在对象写入的先决条件链中。例如,在i=3*i*i中,i的所有三个读取都是计算要写入i的值所必需的,因此它们必须在写入之前执行。但在i=i i;中,对最后一项的i的读取不是写入i的先决条件,因此不一定在写入之前执行。因此,它不符合规则。

...我很困惑,相对于 i 增量操作,获取数组索引的操作不是未排序的吗?

相对于 i 的更新,数组元素的读取是未排序的,这没关系,因为没有规则要求对其进行排序。C 2018 6.5 2 说,强调添加:

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

数组元素是与i不同的标量对象,因此我们不关心数组元素的读取和i的更新之间没有排序。

匿名用户

非常感谢成员的即时回复。我会尝试用我理解的语言来尝试答案。

读了这篇文章后,我建议用抽象树来解决序列点问题(我知道,这不规范)

让我使用抽象语法树表示 a[i ] =1。