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

Sin*_*ngh 1 c language-lawyer

问题长度字数限制..

正如@Karl Knechtel所指出的,我很困惑,是否获取相对于增量操作未排序的数组索引操作i++?如果它们没有排序,为什么 C 标准 6.5.2 行提到(强调添加到我理解的单词/短语中,适用于此处)

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

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

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

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

来自C11标准S6.5.2

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

在阅读了 SO 上的大多数线程(带有标签[C][sequence-points])后,我的理解/推理是 i++ 会导致更新 i 值的副作用。在这种情况下,这个副作用不会被排序到使用相同缩放器对象的值计算。我的理解是a[integer object]构成value computation。那么,它应该是未定义的行为吗?

即使从 C99 S6.5(p2)

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

我理解/解释这个表达式也应该呈现a[i++] = 1未定义?

Eri*_*hil 5

\n

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

\n
\n

涉及的标量对象i++i。相对于 的值的计算,更新的副作用i并不是无序的,i++因为 C 2018 6.5.2.4(指定后缀递增和递减运算符的行为)第 2 段说:

\n
\n

\xe2\x80\xa6 结果的值计算在更新操作数存储值的副作用之前排序\xe2\x80\xa6

\n
\n

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

\n
\n

即使从 C99 S6.5(p2)

\n
\n

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

\n
\n
\n

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

\n

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

\n

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

\n
\n

\xe2\x80\xa6 我很困惑,是否没有获取相对于增量操作未排序的数组索引操作i++

\n
\n

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

\n
\n

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

\n
\n

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

\n