12-求值顺序
7.3.3 求值顺序
除了两个运算符共享一个运算对象的情况外,C通常不保证先对复杂表达式中哪部分求值。例如,下面的语句,可能先对表达式 5 + 3 求值,也可能先对表达式 9 + 6 求值:
apples = (5 + 3) * (9 + 6);
C把先计算哪部分的决定权留给编译器的设计者,以便针对特定系统优化设计。但是,对于逻辑运算符是个例外,C保证逻辑表达式的求值顺序是从左往右。 && 和 || 运算符都是序列点,所以程序在从一个运算对象执行到下一个运算对象之前,所有的副作用都会生效。而且,C保证一旦发现某个元素让整个表达式无效,便立即停止求值。正是由于有这些规定,才能写出这样结构的代码:
while ((c = getchar()) != ' ' && c != '\n')
如上代码所示,读取字符直至遇到第1个空格或换行符。第1个子表达式把读取的值赋给 c ,后面的子表达式会用到 c 的值。如果没有求值顺序的保证,编译器可能在给 c 赋值之前先对后面的表达式求值。
这里还有一个例子:
if (number != 0 && 12/number == 2)
printf("The number is 5 or 6.\n");
如果 number 的值是 0 ,那么第1个子表达式为假,且不再对关系表达式求值。这样避免了把 0 作为除数。许多语言都没有这种特性,知道 number 为 0 后,仍继续检查后面的条件。
最后,考虑这个例子:
while ( x++ < 10 && x + y < 20)
实际上, && 是一个序列点,这保证了在对 && 右侧的表达式求值之前,已经递增了 x 。
小结:逻辑运算符和表达式
逻辑运算符:
逻辑运算符的运算对象通常是关系表达式。!运算符只需要一个运算对象,其他两个逻辑运算符都需要两个运算对象,左侧一个,右侧一个。
| 逻辑运算符 | 含义 |
| :----- | :----- | :----- | :----- |
| && | 与 |
| || | 或 |
| ! | 非 |
逻辑表达式:
当且仅当 expression 1和 expression 2都为真, expression 1 && expression 2才为真。如果 expression 1或 expression 2为真, expression 1 || expression 2为真。如果 expression 为假,! expression 则为真,反之亦然。
求值顺序:
逻辑表达式的求值顺序是从左往右。一旦发现有使整个表达式为假的因素,立即停止求值。
示例:
6 > 2 && 3 == 3 真
!(6 > 2 && 3 == 3) 假
x != 0 && (20 / x ) < 5 只有当 x 不等于0时,才会对第2个表达式求值