什么是"序列点"?
未定义的行为和序列点之间的关系是什么?
我经常使用有趣和复杂的表达方式a[++i] = i;,让自己感觉更好.我为什么要停止使用它们?
如果您已阅读此内容,请务必访问后续问题重新加载未定义的行为和序列点.
(注意:这是Stack Overflow的C++常见问题解答的一个条目.如果你想批评在这种形式下提供常见问题解答的想法,那么发布所有这些的元数据的发布将是这样做的地方.这个问题在C++聊天室中受到监控,其中FAQ的想法一开始就出现了,所以你的答案很可能被那些提出想法的人阅读.)
我在C中编写了一个小型测试应用程序,并在我的Ubuntu 14.04上预装了GCC 4.8.4.我感到困惑的是,表达式的a=(b++);行为方式与此相同a=b++;.使用以下简单代码:
#include <stdint.h>
#include <stdio.h>
int main(int argc, char* argv[]){
uint8_t a1, a2, b1=10, b2=10;
a1=(b1++);
a2=b2++;
printf("a1=%u, a2=%u, b1=%u, b2=%u.\n", a1, a2, b1, b2);
}
Run Code Online (Sandbox Code Playgroud)
gcc编译后的结果是a1=a2=10,而b1=b2=11.但是,我希望括号b1在赋值之前增加a1.
也就是说,a1应该是11而a2平等10.
有没有人对这个问题有所了解?
C11标准(ISO/IEC 9899:2011)在表达式中引入了新的副作用测序定义(参见相关问题).该序列点概念已经补充了之前测序和后序关系,这是现在所有定义的基础.
第6.5节"表达式",第2点说:
如果相对于对同一标量对象的不同副作用或使用相同标量对象的值进行值计算,对标量对象的副作用未被排序,则行为未定义.如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的.
稍后,第6.5.16节"分配操作员",第3点指出:
在左右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序.对操作数的评估是不确定的.
第一个引用的段落(6.5/2)由两个例子支持(与C99标准相同):
a[i++] = i; //! undefined
a[i] = i; // allowed
Run Code Online (Sandbox Code Playgroud)
这可以通过以下定义轻松解释:
因此,i++(LHS)的副作用与i(RHS)无关,这给出了不确定的行为.
i = ++i + 1; //! undefined
i = i + 1; // allowed
Run Code Online (Sandbox Code Playgroud)
但是,此代码似乎在两种情况下都会导致定义的行为:
因此,执行++i + 1
应该在更新的副作用之前i,这意味着相对于对同一标量对象的不同副作用或使用相同标量的值的值计算,对未标测的标量对象没有副作用宾语.
使用C99标准提出的术语和定义很容易解释这些例子(参见相关问题).但i = ++i + 1根据C11的术语,为什么不明确?
考虑下面的程序
#include <stdio.h>
void main(){
int p = -8;
int i = (p++, ++p);
printf("%d\n", i);
}
Run Code Online (Sandbox Code Playgroud)
我无法理解输出为-6的原因.
p++在赋值语句执行后++p会增加,在此之前会增加-8到-7.
怎么i分配-6?