'a [i] = i;' 总是导致明确的行为?

Laz*_*zer 16 c++ undefined-behavior

关于C中未定义的行为,这里提出一些有趣的问题.其中一个是(稍加修改)

以下代码是否会导致未定义的行为?

int i = 0, *a = &i;   // Line 1
a[i] = i + 1;         // Line 2
Run Code Online (Sandbox Code Playgroud)

由于那里对这部分问题没有具体的答案,而且我有兴趣了解C++中的行为,我在这里再次提出它.


来自未定义行为和序列点的规则#2 说

此外,只能访问先前值以确定要存储的值

显然,在上面的例子中,值被访问了两次:a[i](lhs)和i(rhs),并且只有其中一个(rhs)确定要存储的值.

第2行是否违反上述规则并导致C++ 03中的未定义行为?


关于是否i在第2行修改了一些令人困惑的问题?

是的它被修改了!

int*_*jay 18

这将导致C++ 03中的未定义行为,以及C++ 11中明确定义的行为.

C++ 03:未定义的Behvaior

从C++ 03标准,第5节第4段:

在前一个和下一个序列点之间,标量对象应通过表达式的计算最多修改其存储值一次.此外,只能访问先前值以确定要存储的值.

注意第二句:前一个值i只能用于确定要存储的值.但在这里它也用于确定数组索引.因为这个赋值会修改i,a[0] = i+1定义很好,而a[i] = i+1不是.请注意,赋值不会生成序列点:只有完整表达式的末尾(分号)才会生成.


C++ 11:定义良好的行为:

C++ 11摆脱了序列点的概念,而是定义了哪些评估在之前进行了排序.

根据标准,第1.9节第15段:

在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未被排序,则行为未定义.

赋值运算符的两个操作数在实际赋值之前被排序.因此,无论a[i]i+1进行评估,然后才将i被修改.结果很明确.

  • C++ 03和C++ 11答案都是+ 1. (4认同)