我知道这是未定义的行为:
int i = 0;
int a[4];
a[i] = i++; //<--- UB here
因为左侧和右侧的i
评估顺序未定义(;
是唯一的序列点)。
在这个推理上更进一步,在我看来,这将是 undefined 未指明的行为:
int i = 0;
int foo(){
return i++;
}
int main(){
int a[4];
a[i] = foo();
return 0;
}
即使在=
的右侧有一些序列点,据我所知仍然是 undefined 未指定是f()
还是{{1首先评估。
我的假设是否正确?当我在作业的左侧使用全局或静态变量时,我是否必须小心谨慎,右手在任何情况下都不会对其进行修改?
答案 0 :(得分:6)
a[i] = foo();
此处未指定是否首先评估foo
或a[i]
。在新的C ++ 11措辞中,这两个评估没有得到解释。但是,仅此一点不会导致未定义的行为。当对同一个标量对象进行两次未经测试的访问时,至少有一个是在写入的地方,它就是这样做的。这就是为什么a[i] = i++;
是UB。
这两个陈述之间的区别在于对foo()
的调用会引入序列点。 C ++ 11的措辞不同:调用函数内的调用函数内的其他评估对调用函数内的执行进行了不确定的排序。
这意味着a[i]
内的i++
和foo
之间存在部分排序。因此,a[0]
或a[1]
将设置为0,但程序定义良好。
答案 1 :(得分:1)
a[i] = i++;
这是未定义的行为,因为i
的值在两个序列点之间被修改和访问(并且访问不直接参与i
的下一个值的计算)。
这也是未指定的行为,因为未指定评估的顺序(i
的增量可以在使用i
作为a
的索引之前或之后发生。
当您引入函数调用时,例如:
a[i] = foo();
函数调用引入了另外两个序列点:一个在输入函数之前,一个在函数返回之后。
这意味着函数内i
的增量被两个序列点包围,并且不会导致未定义的行为。
虽然在使用i
作为分配左侧的索引之前或之后是否完成函数调用,仍然是未指定的行为。