我正在阅读n3290 C++ 11标准草案(尽可能接近实际标准文本),我注意到会i = i++ + 1;产生未定义的行为.我以前见过类似的问题,但是它们是根据较旧的标准(序列点)来回答的.新标准在表达式和子表达式执行之间的关系之前/之后引入了Sequencing的概念.
1.9 13之前的序列是由单个线程(1.10)执行的评估之间的不对称,传递,成对关系,它在这些评估中引起部分顺序.给定任何两个评估A和B,如果A在B之前被排序,那么A的执行应该在B的执行之前.如果A在B之前没有排序,而B在A之前没有排序,那么A和B是未排序的.[注意:未经测试的评估的执行可能会重叠.-end note]评估A和B是不确定的顺序,当A在A之前测序或B在A之前测序,但未指定哪一个.[注意:不确定顺序的评估不能重叠,但可以先执行. - 尾注]
1.9 14在与要评估的下一个全表达式相关的每个值计算和副作用之前,对与全表达式相关的每个值计算和副作用进行排序.
1.9 15除非另有说明,否则对个体操作员的操作数和个别表达式的子表达式的评估是不确定的.[注意:在程序执行期间不止一次评估的表达式中,不需要在不同的评估中一致地执行对其子表达式的未序列和不确定顺序的评估.-end note]运算符操作数的值计算在运算符结果的值计算之前排序.如果对标量对象的副作用相对于对同一标量对象的其他影响或使用相同标量对象的值进行的值计算未进行排序,则行为未定义.
[ Example:
void f(int, int);
void g(int i, int* v) {
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined
i = i + 1; // the value of i is incremented
f(i = -1, i = -1); // …Run Code Online (Sandbox Code Playgroud) 我读了几个关于未定义行为和序列点的非常好的答案(例如未定义的行为和序列点),我明白了
int i = 1;
a = i + i++; //this is undefined behaviour
Run Code Online (Sandbox Code Playgroud)
根据C++标准,是未定义的代码.但是,未定义的行为背后的深层原因是什么?是否足以使其成为未指明的行为?正常的论点是,通过几个序列点,C++编译器可以更好地针对不同的体系结构进行优化,但是不会让它未指定允许这些优化吗?在
a = foo(bar(1), bar(2)); //this is unspecified behaviour
Run Code Online (Sandbox Code Playgroud)
编译器也可以优化,并且它不是未定义的行为.在第一个例子中,似乎很清楚,a是2或3,所以语义似乎对我来说很清楚.我希望有一个推理,为什么有些东西是未指定的,有些是未定义的.
阅读有关ACCU过载的有趣文章#115:"恶魔可能会飞出你的鼻子"我发现作者说:
在序列点之间,不允许对涉及变量的状态做出任何假设.这也意味着在C中,与大多数其他语言不同,以下表达式会导致未定义的行为
v [i] = i ++;
因为赋值运算符不代表C中的序列点
有人可以解释一下UB的详细推理是什么吗?我认为在两个序列点之间对同一个变量进行多次写操作是个问题,除了v [i]别名的可能性之外我在这里看不到...