逻辑运算

关系运算符使我们具有表达单一条件的能力,而逻辑运算让我们拥有多个关系处理的可能。

加减(+、-)运算需要左右两个操作数,如a+b;与此类似,与或运算(&&、||)需要左右两个关系表达式,它们具有从左向右的结合性。如,a && b,表示先计算表达式a,成立的话再计算表达式b。赋值运算符(=)用于将右端值赋给左边变量,这被称为右结合性,非运算(!)与之类似,也具有右结合性;!0表示非0,即为真。

假设expr1和expr2是两个关系表达式,那么可以声明如下:

#include <stdio.h>

int main()
{
    int a = 9;
    int b = 0;

    printf("3 && 7: %d\n", (3 && 7));
    printf("a && b: %d\n", (a && b));
    printf("b && a: %d\n", (b && a));

    printf("3 || a: %d\n", (3 || a));
    printf("b || a: %d\n", (b || a));

    printf("!3:     %d\n", !3);
    printf("!b:     %d\n", !b);

    return 0;
}

glimix.com

下面是例子的分析,注释后的第一列表示整个逻辑运算的结果,以短横线分隔的文本分别表示表达式的真假值。

3 && 7      // true  - 3(true) && 7(true)
a && b      // false - a(true) && b(false)
b && a      // false - b(false)

3 || a      // true - 3(true)
b || a      // true - b(false) || a(true)

!3          // false - !3(true)
!b          // true  - !b(false)

留意一下,在 &&、|| 运算中,第二个表达式有不需要计算的情形,如:

这也表明:

通过逻辑运算符,可以将多个条件组织起来,形成更复杂的条件判断。

#include <stdio.h>

int main()
{
    int a = 9;
    int b = 0;
    int c = 2;

    printf("(a && b) || (c >= 2) : %d\n", (a && b) || (c >= 2));
    printf("c > 2 && c < 9       : %d\n", c > 2 && c < 9);
    printf("!b || !a             : %d\n", !b || !a);

    return 0;
}

glimix.com

不恰当的表达

上面的例子中,我们使用

c > 2 && c < 9

来表达c位于一个区间的概念,在数学上,这可以写作:

2 < c < 9

但是在C语言中,这种表达是语义错误的,假设c的值为10,表达的计算过程如下:

  1. 计算表达式 2 < 10:为true
  2. 计算表达式 true < 9 而不是 10 < 9:右侧9是整数,true从bool转型到1,变成1<9,求值为true
  3. 整体表达式 2 < c < 10,求值为true

显然,这里的数学表示法并不能表达我们真正的意图,但它们却是有效的代码。与此类似,要比较3个数值是否相等,也不能用数学方法编写代码。

#include <stdio.h>

int main()
{
    int c = 2;
    printf("2 < c < 9   : %d\n", 2 < c < 9);

    int a = 9, b = 9;
    c = 9;
    printf("a == b == c : %d\n", a == b == c);

    return 0;
}

glimix.com

最后,对于表达式中的关系与逻辑运算符的优先级,如:

c > 2 && c < 9

我们的本能是先判断 c>2,成立后再判断 c<9,最后将两者结果比较。这种语言设计上的特性也符合人的思维模式,因而,关系运算符优先级高于逻辑运算符。

练习

1 逻辑运算的短路模式带给你哪些编程启示?

2 将目前学过的运算符组织到逻辑运算中,看看有什么收获。

3 编写一段判断三个数是否相等的代码。

陕ICP备2025078817号-1 陕公网安备61011202001108号