浅谈C/C++中的顺序点和副作用

 

一.副作用(side effect)
    表达式有两种功能:每个表达式都产生一个值( value ),同时可能包含副作用( side effect )。副作用是指改变了某些变量的值。
    如:
    1:20 //这个表达式的值是20;它没有副作用,因为它没有改变任何变量的值。
    2:x=5 // 这个表达式的值是5;它有一个副作用,因为它改变了变量x的值。
    3:x=y++ // 这个表示有两个副作用,因为改变了两个变量的值。
    4:x=x++ // 这个表单时也有两个副作用,因为变量x的值发生了两次改变。
    二.求值顺序点
    表达式求值规则的核心在于 顺序点( sequence point ) [ C99 6.5 Expressions 条款2 ] [ C++03 5 Expressions 概述 条款4 ]。
    顺序点的意思是在一系列步骤中的一个“结算”的点,语言要求这一时刻的求值和副作用全部完成,才能进入下面的部分。在C/C++中只有以下几种存在顺序点:
    1)分号;
    2)未重载的逗号运算符的左操作数赋值之后(即','处)
    3)未重载的'||'运算符的左操作数赋值之后(即'||'处);
    4)未重载的'&&'运算符的左操作数赋值之后(即“&&”处);
    5)三元运算符'? : '的左操作数赋值之后(即'?'处);
    6)在函数所有参数赋值之后但在函数第一条语句执行之前;
    7)在函数返回值已拷贝给调用者之后但在该函数之外的代码执行之前;
    8)每个基类和成员初始化之后;
    9)在每一个完整的变量声明处有一个顺序点,例如int i, j;中逗号和分号处分别有一个顺序点;
    10)for循环控制条件中的两个分号处各有一个顺序点。
    对于任意一个顺序点,它之前的所有副作用都已经完成,它之后的所有副作用都尚未发生。
    在两个顺序点之间,子表达式求值和副作用的顺序是不同步的。如果代码的结果与求值和副作用发生顺序相关,称这样的代码有不确定的行为(unspecified behavior).而且,假如期间对一个内建类型执行一次以上的写操作,则是未定义行为.
    任意两个顺序点之间的副作用的发生顺序都是未定义的.
    如:
    x=x++;
    该表达式只有一个顺序点,在该顺序点之前有2个副作用,一个是自增,一个赋值,这两个副作用发生的顺序是未定义的,即自增运算和赋值运算哪一个先执行是没有被定义的(注意这个顺序跟运算符的优先级是无关的,注意理解运算符优先级的含义),这个执行次序交由编译器厂商去自行决定,因此对于不同的编译器可能会得出不同的结果。
    #include
    #include
    int main(int argc, char *argv[])
    {
    int i=0;
    int m=(++i)+(++i)+(++i)+(++i);
    printf("%d %d\n",m,i);
    system("pause");
    return 0;
    }

你可能感兴趣的:(浅谈C/C++中的顺序点和副作用)