7.3 逻辑运算符
有时,把多个关系表达式组合起来会很有用。
使用逻辑运算符
// chcount.c -- use the logical AND operator
#include <stdio.h>
#define PERIOD '.'
int main(void)
{
char ch;
int charcount = 0;
while ((ch = getchar()) != PERIOD)
{
if (ch != '"' && ch != '\'')
charcount++;
}
printf("There are %d non-quote characters.\n", charcount);
return 0;
}
/* 输出:
*/
逻辑运算符&&两侧的条件必须都为真,整个表达式才为真。逻辑运算符的优先级比关系运算符低,所以不必在子表达式两侧加圆括号。
C有3种逻辑运算符,见表7.3。
表7.3 3种逻辑运算符
逻辑运算符 含义
&& 与
|| 或
! 非
假设exp1和exp2是两个简单的关系表达式,那么:
*当且仅当exp1和exp2都为真时,exp1 && exp2才为真;
*如果exp1或exp2为真,则exp1 || exp2为真;
*如果exp1为假,则!exp1为真;如果exp1为真,则!exp1为假。
!(4 > 7) 与 4 <= 7表达式等价。
请记住:(练习&&时间)== 完美。
7.3.1 备选拼写:iso646.h头文件
C是在美国用标准键盘开发的语言。但是在世界各地,并非所有的键盘都有和美式键盘一样的符号。因此,C99标准新增了可代替逻辑运算符的拼写,它们被定义在iso646.h头文件中。如果在程序中包含该头文件,便可用and代替&&,or代替||,not代替!。例如,可以把下面的代码:
if( ch != '"' && ch != '\'' ){
...
}
改写为:
if( ch != '"' and ch != '\'' ){
...
}
C不直接使用and、or和not的原因是C一直坚持尽量保留较少的关键字。
表7.4 逻辑运算符的备选拼写
传统写法 iso646.h
&& and
|| or
! not
7.3.2 优先级
!运算符的优先级很高,比乘法运算符还高,与递增运算符的优先级相同,只比圆括号的优先级低。&&运算符的优先级比||运算符高,但是两者的优先级都比关系运算符低,比赋值运算符高。
使用圆括号可以使表达式的含义更清楚明了。
7.3.3 求值顺序
除了两个运算符共享一个运算符对象的情况外,C通常不保证先对复杂表达式哪部分求值。但是,对于逻辑运算符是个例外,C保证逻辑表达式的求值顺序是从左到右。&&和||运算符都是序列点,所以程序在从一个运算对象执行到下一个运算对象之前,所有的副作用都会生效。而且,C保证一旦发现某个元素让整个表达式无效,便立即停止求值。正是由于有这些规定,才能写出这样结构的代码:
while( (c = getchar()) != ' ' && c != '\n' )
保证了必须先执行赋值操作再进行比较操作。
if( number != 0 && 12 / number == 2 )
保证了number不等于0时才执行除法操作。
while( x++ < 10 && x + y < 20 ) //
&&是一个序列点,这保证了在对&&右侧的表达式求值之前,已经递增了x。
7.3.4 范围
&&运算符可用于测试范围。可以这样写:
if( range >= 90 && range <= 100 ){
...
}
千万不要模仿数学上的写法:
if( 90 <= range <= 100 ) //千万不要这样写
这样写的问题是有语义错误,而不是语法错误,所以编译器不会捕获这样的问题。由于<=运算符的求值顺序是从左到右,所以编译器把测试表达式解释为:
(90 <= range) <= 100
整个表达式都恒为真。因此,在范围测试中要使用&&。
ASCII字符编码内有效:
if( ch >= 'a' && ch <= 'z' ){
...
}
相应的可移植方法是用ctype.h系列中的islower()函数。
if( islower( ch ) ){
...
}
无论使用那种特定的字符编码,islower()函数都能正常运行。