首先弄清楚一个问题:求值顺序不是运算顺序
Q:什么是运算顺序?
A:运算顺序就是根据运算符号的优先级(结合性)来进行求值的过程
Q:什么是求值过程?
A:举个例子吧, D = A + B + C, 运算顺序是 A 先加 B 再加 C, 但是c语言并没有规定是先计算A的值还是B的值还是C的值; 这就是求值顺序。
求值顺序在某些情况下很值得注意
比如: f(), g(), h()是三个函数, 现在 a = f() + g() + h(), 运算顺序保证了f()首先与g()相加然后再加h(), 但是先计算哪个函数的值是不确定的[可能是f(), 可能是g(), 也可能是h()]。如果f(), g(), h()里面都引用了某个全局变量(不一定非要是全局变量), 那么先计算某个函数的值导致的 最后结果 a 也会不一样。比如: 你认为f()函数先调用, 然后是g(), 最后是h(); 这样在g()函数里面调用的全局变量的值就是 f()函数已经操作过的(可能已经更改), 同样h()操作的全局变量是已经经过了f()和g()函数操作的。但是事实上编译器并不一定要先计算f()函数, 相反可能会先计算h()函数, 这样 最后 a 的值就与你想象中的不是同一个数字。
c语言中有四个运算符规定了求值顺序
- &&
- ||
- ?:
- ,
解释:
- 对于&&和||运算符, 首先对做操作数进行求值, 如果这个表达式的值已经确定了, 那么不会对有操作数求值。对于三目运算符, a?b:c; 首先对操作数a求值, 根据a的值求操作数b或者c的值。对于逗号运算符, 首先对左操作数就进行求值, 然后将该值“丢弃”, 再对右操作数进行求值。
最后引用c陷阱与缺陷中的一个例子
下面这种从数组x中复制前n元素到数组y中的做法是不正确的, 因为对求值顺序进行了太多假设:
i = 0;
while(i < n)
y[i] = x[i++]
问题出在哪里呢? 上面的代码假设y[i]的地址将在i的自增操作执行之前被求值, 这一点并没有任何保证!在C语言的某些实现上, 有可能在i自增之前被求值; 而在另外的一些实现上, 有可能与此相反。同样的道理, 下面这种版本的写法与前类似, 也不正确
i = 0;
while(i<n)
y[i++] = x[i];
而另一方面, 下面这种写法却能正常工作:
i = 0;
while(i < n)
{
y[i] = x[i];
i++
}
当然这种写法可以简写为:
`for (i = 0; i < n; i++)
{
y[i] = x[i];
}