7

我知道这是未定义的行为:

int i = 0;
int a[4];
a[i] = i++;  //<--- UB here

i因为左侧和右侧的评估顺序未定义(这;是唯一的序列点)。

进一步推理,在我看来,这将是不明确的未指定的行为:

int i = 0;

int foo(){
    return i++;
}

int main(){
    int a[4];
    a[i] = foo();
    return 0;
}

=尽管据我所知,右侧有几个序列点仍然是不明确的未指定是否先评估f()a[i]先评估。

我的假设正确吗?当我在赋值的左侧使用全局或静态变量而右手在任何情况下都不会修改它时,我是否必须小心谨慎?

4

2 回答 2

6
a[i] = foo();

此处未指定是否先评估fooa[i]先评估。在新的 C++11 措辞中,这两个评估是无序的。不过,仅此一项并不会导致未定义的行为。当对同一个标量对象进行两次未排序的访问时,其中至少一个是写入,它确实如此。这就是为什么a[i] = i++;是UB。

这两个语句之间的区别在于调用foo()确实引入了一个序列点。C++11 的措辞不同:被调用函数内部的执行相对于调用函数内部的其他计算是不确定的。

a[i]这意味着和i++inside之间存在部分排序foo。结果,要么 要么a[0]a[1]设置为 0,但程序定义明确。

于 2014-04-08T15:07:59.123 回答
1
a[i] = i++;

这是未定义的行为,因为 的值i在两个序列点之间被修改和访问(并且访问不直接参与 的下一个值的计算i)。这也是未指定的行为,因为评估的顺序是未指定的(的增量i可以发生在i用作索引之前或之后a)。

当您引入函数调用时,例如:

a[i] = foo();

函数调用引入了另外两个序列点:一个在函数进入之前,一个在函数返回之后。

这意味着i函数内部的增量被两个序列点包围,并且不会导致未定义的行为。

i尽管函数调用是在用作赋值左侧的索引之前还是之后完成,但它仍然是未指定的行为。

于 2014-04-08T15:07:29.903 回答