ITEEDU

2.19 逻辑运算符

前面只介绍了courter<=10、total>1000和number!=sentinel Value之类的简单条件(simplecondition)。我们用关系运算符>、<、>=、<=和相等运算符==、!=表示这些条件。每个判断只测试一个条件。要在每个判断中测试多个条件,可以在不同语句中或嵌套if(if/else)结构中进行这些测试。

C++提供的逻辑运算符(logical operator)可以用简单条件组合成复杂条件。逻辑运算符有逻辑与( &&)、逻辑或(||)和逻辑非(!),下面将举例说明。

假设要保证两个条件均为true之后再选择某个执行路径,这时可以用 &&逻辑运算符:

if { gender == 1&& age>= 65 )

++senior Females;

这个if语句包含两个简单条件。条件gender==1确定这个人是男是女,条件age>=65确定这个人是否为老年人。&&逻辑运算符左边的简单条件先求值,因为::的优先级高于&&。如果需要,再对&&逻辑运算符右边的简单条件求值,因为>=的优先级高级于&&(稍后将会介绍,&&逻辑运算符右边的条件只在左边为true时才求值)。然后if语句考虑下列组合条件:

gender==l  &&age>=65

如果两边的简单条件均为true,则这个条件为true。最后.如果这个条件为true,则seniorFemales递增1。如果两边的简单条件有一个为false,则程序跳过该递增,处理if后面的语句。上述组合条件可以通过增加多余的括号而变得更加清楚:

(gender==1)  &&(age>=65)
常见编程错误2.24

尽管3<x<7条件在数学上是正确的,但在C++中无法正确求值,应改成(3<x&&x<7)。

图2.28的表格总结了 &&逻辑运算符。表中显示了表达式1和表达式2的四种false和true值组合,这种表称为真值表(truth table)。C++对所有包括逻辑运算符、相等运算符和关系运算符的所有表达式求值为false或true。

 表达式1                        表达式2                表达式1&&表达式2 
    false                          false                    false
    false                          true                     false
    true                           false                    false
    true                           true                     true 
图 2.28 逻辑与(&&)运算符真值表
可移植性提示2.5

为了与旧版C++标准兼容,bool值为true表示任何非0值,bool值为false表示0值。

下面考虑逻辑或运算符(||)。假设要保证两个条件至少有一个为true之后再选择某个执行路径,这时可以用逻辑或运算符,如下列程序段所示:

if(semesterAverage)>=90 ||finalExam>=90)
    cout<<"Student grade   is   A"<<endl;

上述条件也包含两个简单条件。条件semesterAverage>=90确定学生整个学期的表现是否为"A",条件finalExam>=90确定该生期末考试成绩是否优秀。然后if语句考虑下列组合条件:

semesterAverage>=90 ||   finalExam>=90

如果两个简单条件至少有一个为true,则该生评为“A”。注意只有在两个简单条件均为false时才不打印消息"Student grade is A"。图2.29是逻辑或(||)运算符的真值表。

&&逻辑运算符的优先级高于||运算符。这两个运算符都是从左向右结合。包含&&和||运算符的表达式只在知道真假值时才求值。

这样,求值下列表达式:

gender==1 && age>=65

将在gender不等于1时立即停止(整个表达式为false),而gender等于1时则继续求值(整个表达式在age>=65为true时为true。

 表达式1                    表达式2                    表达式1&&表达式2 
    false                      false                      false
    false                      true                       true
    true                       false                      true
    true                       true                       true 

图 2.29 逻辑或(||)运算符真值表
常见编程错误2.25

在使用&&逻辑运算符的表达式中,一个条件(称为相关备件)要在另一个条件为true时才有求值的必要。这时,相关条件应放在另一条件的后面,否则可能发生错误。

性能提示2.10

在使用&&逻辑运算符的表达式中,如果两个条件是相互独立的,则应把false可能性较大的条件放在左边;在使用||逻辑运算符的表达式中,应把true可能性较大的条件放在左边。这样可以减少程序执行时间。

C++提供了逻辑非(!)运算符,使程序员可以逆转条件的意义。与&&和||运算符不同的是,&&和||运算符组合两个条件(是二元运算符),而逻辑非(!)运算符只有一个操作数(是一元运算符)。逻辑非(!)运算符放在条件之前,在原条件(不带逻辑非运算符的条件)为false时选择执行路径,例如:

if(grade!=sentinelValue)
   cout<<"The next grade  is"<<grade<<endl;

这种灵活性有助于程序员以更自然或更方便的方式表达条件。

图2.31显示了前面介绍的c++运算符的优先级和结合律。运算符优先级从上到下逐渐降低。

   运算符                                          结合律            类型 
    ()                                            从左向右           括号
    ++  --  +  -  !  static_cast()                从右向左           一元
    *  /  %                                       从左向右           乘
    +  -                                          从左向右           加
    <<  >>                                        从左向右           插入/读取
    <  <=  >  >=                                  从左向右           关系
    ==  !=                                        从左向右           相等
    &&                                            从左向右           逻辑与
    ||                                            从左向右           逻辑或
    ?:                                            从右向左           条件
    =  +=  -=  *=  /=  %=                         从右向左           赋值
    ,                                             从左向右           逗号 
图 2.31   运算符优先级和结合律

2.20 混淆相等(==)与赋值(=)运算符

这是C++程序员常见的错误,包括熟练的C++程序员也会把相等(==)与赋值(=)运算符相 混淆。这种错误的破坏性在于它们通常不会导致语法错误,而是能够顺利编译,程序运行完后,因为运行时的逻辑错误而得到错误结果。

C++有两个方面会导致这些问题。一个是任何产生数值的表达式都可以用于任何控制结构的判断部分。如果数值为0,则当作false,如果数值为非0,则当作true。第二是C++赋值会产生一个值,即赋值运算符左边变量所取得的值。例如,假设把下列代码:

if(payCode==4) 
 cout<<"You get a bonus!" << endl;

误写成如下形式:

if(payCode=4)  
  cout   <<  "You get a bonus!" <<   endl;

第一个if语句对paycode等于4的人发奖金。而第二个if语句则求值if条件中的赋值表达式为常量4。由于非0值解释为true,因此这个if语句的条件总是true,则人人都获得一份奖金,不管其paycode为多少。更糟的是,本来只要检查paycode,却已经修改了Poycode。

常见编程错误2.26

用==运算符进行赋值或用=运算符表示相等是个逻辑错误。

测试与调试提示2.1

程序员通常将条件写成x==7,即变量名在左边,常量在右边。如果反过来.即变量名在右边,常量在左边,写成7==x,刚编译器能防止程序员把==运算符写成=。编译器把这个错误当作语法错误,因为赋值语句左边只能放变量名.这样至少可以防止运行时逻辑错误的潜在破坏。

变量名可称为左值(lvalue),因为它可以放在赋值运算符左边。常量称为右值(rvalue),因为它只能放在赋值运算符右边。注意,左值可以作为右值,但右值不能用作左值。

还有一个问题也同样麻烦。假设程序员要用下列简单涪句给一个变量赋值:

x = 1;

但却写成:

x == 1;

这也不是语法错误,编译器只是求值条件表达式。如果x等于1,则条件为true,表达式返回true值。

如果x不等于1,则条件为false,表达式返回false值。不管返回什么值都没有赋值运算符,因此这个值丢失,x值保持不变,有可能造成执行时的逻辑错误。但这个问题没有简单的解决办法。

测试与调试提示2.2
用文本编辑器搜索程序中的所有=,检查是否为正确的运算符。