4.4 表达复杂的条件

1.逻辑运算符及运算规则

C语言中提供了3种逻辑运算符(Logical Operators):

1) && 逻辑与运算(Logical AND Operator)

2) || 逻辑或运算(Logical OR Operator)

3) ! 逻辑非运算(Logical Negation Operator)

&&和||均为二元运算符,由左向右结合。!为一元运算符,从右向左结合(一元运算符都是从右向左)。整数类型和浮点类型(5)都可以作为逻辑运算的运算对象,得到的值是int类型。这几个运算的运算规则如表4-1所示。

表4-1 &&、||、!的运算规则

4.4 表达复杂的条件 - 图1

!运算符的优先级为15,与一元运算符“+”、一元运算符“-”、sizeof运算同级。

&&运算符的优先级为5,||运算符的优先级为4,均低于判等运算符,高于赋值运算符。

请注意,对于逻辑非!这个运算符号,哲学上的否定之否定规律是不成立的,比如:

4.4 表达复杂的条件 - 图2

的值为1而不是2。换句话说对于某个数据x,!!x的结果不一定是x。

练习

1.显然(zzs>=1)&&(zzs<=12)的值为1表示的是(zzs>=1)和(zzs<=12)同时成或,且!!((zzs>=1)&&(zzs<=12))的值为1可以表示(zzs>=1)和(zzs<=12)不同时成立(注意不是同时不成立)。进一步研究还可以发现!!((zzs>=1)&&(zzs<=12))完全等价于!!(zzs>=1)||!(zzs<=12)或(zzs<1)||(zzs>12)。利用这些事实改写程序代码4-4。

2.输入一字符,判断这个字符是否是英文字母。

2.&&和||运算的序点

C语言规定,在进行&&或||运算时,编译器一定要保证先求&&或||左面表达式的值,并实现其全部副效应。如果这个值已经决定了逻辑运算的结果,那么不再求&&或||右面表达式的值;如果这个值不足以确定逻辑运算的最后结果,再求&&或||右面表达式的值。

在某个点之前,全部运算及副效应必须完成,这种点就是所谓的序点。&&或||都属于C语言中的序点。

举例来说,对于下面的表达式:

4.4 表达复杂的条件 - 图3

由于&&左面的值为0,此时无论&&右面的表达式的值为多少,整个表达式的值都为0,这时不再计算&&右面的表达式(j=3)的值,因此j=3也就得不到执行。但若是:

4.4 表达复杂的条件 - 图4

这样的表达式,由于||左面的值为0,尚不足以确定逻辑运算的最后结果,因此需要求(j=3)的值,这样j将会被赋值为3。

&&或||的这种运算次序的特殊性表明,在代码中,如果&&或||的右面有改变变量值的运算,那么这种自作聪明的打算很可能是会落空的。进而,完全可以说,这样的代码片段是不合格的代码片段,是不可以出现在代码中的(6)。因为这样的逻辑表达已经超出了人类的理解能力和描述能力。

练习

1.写出下面各表达式的等价表达式:

!(a<b) !(a<=b+3) !(a<b&&c<d) !(a+1=b+1) !(a>2||a<5)!(a<1||b<2&&c<3)

2.写出表达式的值。

1<4&&4<7 2>6&&3<=8 !(2<=5) !2<=5 !(1<3)||(2<4) !(1<3||(2<4)) !(2<=6&&3<=7) 3+!2<6-7 3&&8&&3||4 7<6+5||4-2