当v有副作用时,其实v+=e不等于v=v+e
计算v+=e只会求一次v的值,而计算v=v+e则会求两次v的值。在后一种情况下,对v求值可能引起的任何副作用也都会出现两次。
a[i++] += 2; //i只会自增一次
如果用=代替+=,变成:
a[i++] = a[i++] + 2;
//i的值在别处被修改和使用了,因此上述语句的结果是未定义的。i的值可能会自增两次,无法确定发生了什么。
(通常我们不希望运算符改变它们的操作数,数学中的运算符就是如此。表达式i+j不会改变i或j的值,只是计算出i+j的结果。
大多数C语言运算符不会改变操作数的值,但是也有一些会改变。由于这类运算符所做的不再仅仅是计算出值,所以称它们有副作用(side effect)。如赋值运算符)
(子表达式的求值顺序------C语言没有规定子表达式的求值顺序
像 c = (b=a+2) - (a=1);//执行结果是未定义的,表达式(b=a+2) - (a=1),是先计算(b=a+2)还是(a=1)没有专门规定,由编译器决定,而结果又依赖于求值顺序.
C语言中只有四个运算符&&,||,?:和,号存在规定的求值顺序。&&,||首先对左侧操作数求值,只在需要时才对右侧操作数求值。运算符?:有三个操作数,在a?b:c中,操作数a首先被求值,根据a的值再求操作数b或c的值。而逗号运算符,首先对左侧操作数求值,然后该值被“丢弃”,再对右侧操作数求值。
注:
分隔函数参数的逗号并非逗号运算符。例如,x和y在函数f(x,y)中的求值顺序的未定义的,而在函数g((x,y))中却是确定的先x后y的顺序。在后一个例子中,函数g只有一个参数,这个参数的值是这样求得的。先求x,然后x的值被“丢弃”,接着求y的值)