C语言::细说那些容易搞混淆的与、或、非 - 高小调博客

C语言::细说那些容易搞混淆的与、或、非

初学C语言的同学经常会把逻辑操作符中的逻辑与、逻辑或与位操作符中的按位与、按位或、按位非搞混。今天我就来分享一下C语言中很容易混淆的那些与、或、非.

逻辑操作符

1.逻辑与(&&)

参与逻辑与(&&)计算的对象,只有两种:要么0,要么非0

逻辑与(&&)计算后结果只有两种:要么0,要么1.

只有逻辑与(&&)两边的对象同时为非0时,其值为1.

1
2
3
4
printf("%u\n",2&&3); //1
printf("%u\n",2&&0); //0
printf("%u\n",0&&0); //0
printf("%u\n",0&&3); //0

在多个表达式参与逻辑与(&&)计算时,比如这样:

a&&b&&c&&d&&e

如果前面的结果里出现了0,后面的表达式将不会参与计算.

比如以下程序:

1
2
3
4
5
6
7
#include<stdio.h>
int main(){
    int i = 0;
    printf("%u\n",++i&&i++&&0&&i++&&(i=100));
    printf("%u\n",i);
    return 0;
}

最终i会输出几?和你想象的一样嘛?

2.逻辑或(||)

参与逻辑或(||)计算的对象,只有两种:要么0,要么非0

逻辑或(||)计算后结果也只有两种:要么0,要么1.

只有参与逻辑或(||)的表达式全为0时,逻辑或(||)的计算结果才为0.

1
2
3
4
printf("%u\n",2||3); //1
printf("%u\n",2||0); //1
printf("%u\n",0||0); //0
printf("%u\n",0||3); //1

如果前面的结果里出现了1,后面的表达式将不会参与计算.

同样的下面的代码,最终i会输出几?

1
2
3
4
5
6
7
#include<stdio.h>
int main(){
    int i = 0;
    printf("%u\n",i++||i++||0||i++||(i=100));
    printf("%u\n",i);
    return 0;
}

位操作符

我们知道,在计算机中,变量的存储都是以它二进制的补码形式作为存储的.

正数的原码、反码、补码相同.

负数的反码:除去符号位,其他位按位取反.

(二进制中最高位是符号位)

负数的补码:负数的反码+1.

同时非常重要的一个结论就是:补码的补码等于它的原码

1.按位与(&)

参与按位与(&)运算的数可以是任意数.

最终的得到结果就是两个数补码进行按位与之后得到的数字.

例子一:

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //补码:00000000 00000000 00000000 00000011
    int b = 3;
    //补码:00000000 00000000 00000000 00000010
    //a&b最终得到2
    printf("%d\n",a&b);
    return 0;
}

例子二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:00000000 00000000 00000000 00000000
    //反码:11111111 11111111 11111111 11111111
    //原码:00000000 00000000 00000000 00000000
    //a&b最终得到0
    printf("%d\n",a&b);
    return 0;
}

例子三:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
int main(){
    //原码:10000000 00000000 00000000 00000010
    //反码:11111111 11111111 11111111 11111101
    //补码:11111111 11111111 11111111 11111110
    int a = -2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:11111111 11111111 11111111 11111100
    //反码:10000000 00000000 00000000 00000011
    //原码:10000000 00000000 00000000 00000100
    //a&b最终得到-4
    printf("%d\n",a&b);
    return 0;
}

2.按位或(|)

参与按位或(|)运算的数可以是任意数.

最终的得到结果就是两个数补码进行按位或(|)之后得到的数字.

例子一:

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //补码:00000000 00000000 00000000 00000011
    int b = 3;
    //补码:00000000 00000000 00000000 00000011
    //a|b最终得到3
    printf("%d\n",a|b);
    return 0;
}

例子二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:11111111 11111111 11111111 11111111
    //反码:10000000 00000000 00000000 00000000
    //原码:10000000 00000000 00000000 00000001
    //a|b最终得到-1
    printf("%d\n",a|b);
    return 0;
}

例子三:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
int main(){
    //原码:10000000 00000000 00000000 00000010
    //反码:11111111 11111111 11111111 11111101
    //补码:11111111 11111111 11111111 11111110
    int a = -2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:11111111 11111111 11111111 11111111
    //反码:10000000 00000000 00000000 00000000
    //原码:10000000 00000000 00000000 00000001
    //a|b最终得到-1
    printf("%d\n",a|b);
    return 0;
}

3.按位取反(~)

参与按位取反(~)计算的数字也可以是任意数.

最终计算结果就是变量二进制补码取反后的结果.

综合例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:11111111 11111111 11111111 11111101
    //反码:10000000 00000000 00000000 00000010
    //原码:10000000 00000000 00000000 00000011
    //~a最终得到3
    printf("%d\n",~a);
    //补码:00000000 00000000 00000000 00000010
    //~b的反码符号位为0,所以是正数,因此补码等于原码.
    //~b最终结果为2
    printf("%d\n",~b);
    return 0;
}

附加4.异或(^)

异或(^)最终计算结果就是变量二进制补码取异或后的结果.

(异或计算:相同为0,相异为1)

例子一:

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //补码:00000000 00000000 00000000 00000011
    int b = 3;
    //补码:00000000 00000000 00000000 00000001
    //a^b最终得到1
    printf("%d\n",a^b);
    return 0;
}

例子二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
int main(){
    //补码:00000000 00000000 00000000 00000010
    int a = 2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:11111111 11111111 11111111 11111111
    //反码:10000000 00000000 00000000 00000000
    //原码:10000000 00000000 00000000 00000001
    //a^b最终得到-1
    printf("%d\n",a^b);
    return 0;
}

例子三:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
int main(){
    //原码:10000000 00000000 00000000 00000010
    //反码:11111111 11111111 11111111 11111101
    //补码:11111111 11111111 11111111 11111110
    int a = -2;
    //原码:10000000 00000000 00000000 00000011
    //反码:11111111 11111111 11111111 11111100
    //补码:11111111 11111111 11111111 11111101
    int b = -3;
    //补码:00000000 00000000 00000000 00000011
    //最高位符号位为0,所以是正数,正数原、反、补相同
    //因此a^b最终得到3
    printf("%d\n",a^b);
    return 0;
}

写到这里,相信大家对逻辑与、逻辑或、按位与、按位或已经有清晰的了解了吧!

希望大家再也不会犯把逻辑与按位与搞混的低级错误了!

    扩展阅读
  1. printf()函数功能、原型、用法和实例
上一篇:
下一篇: