在 C 语言中,相同的数字可以用不同的数制来表示。也就是十进制的数字可以等价的表示为二进制或者十六进制。那么对于二进制来说,可以进行逐个数字之间,也就是每一个数字位的运算。这种运算也广泛的存在我们日程使用的数字电路中。其实计算机的运算原理最底层就是位运算,也...
在 C 语言中,相同的数字可以用不同的数制来表示。也就是十进制的数字可以等价的表示为二进制或者十六进制。那么对于二进制来说,可以进行逐个数字之间,也就是每一个数字位的运算。这种运算也广泛的存在我们日程使用的数字电路中。其实计算机的运算原理最底层就是位运算,也就是 0 和 1 的运算。
运算符 | 作用 | 示例 |
---|---|---|
& | 位与 | a&b |
| | 位或 | a|b |
^ | 位异或 | a^b |
~ | 位非 | ~b |
<< | 位左移 | a<<b |
>> | 位右移 | a>>b |
对于位运算中的与、或、异或可以通过下面的表格来阐明。
x | y | x & y | x | y | x ^ y |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
对于非操作符有下表的结果。
x | ~x |
---|---|
0 | 1 |
1 | 0 |
移位操作就是将位向左或者向右移动,空位用 0 来补齐。
# include <stdio.h>
int main()
{
int x,y,z;
x=10; // 10 = 1010
y=15; // 15 = 1111
z=x&y;
printf("x & y = %d\n", z);
z=x|y;
printf("x | y = %d\n", z);
z=x^y;
printf("x ^ y = %d\n", z);
z=~x;
printf("~ x = %d\n", z);
z=~y;
printf("~ y = %d\n", z);
z=x<<2;
printf("x << 2 = %d\n", z);
z=y>>2;
printf("x >> 2 = %d\n", z);
return 0;
}
运行结果如下:
x & y = 10
x | y = 15
x ^ y = 5
~ x = -11
~ y = -16
x << 2 = 40
x >> 2 = 3
那么我们分析一下这些结果。
10 = 1 0 1 0
15 = 1 1 1 1
10 & 15 = 1 0 1 0
按照上节的表格计算后,发现 10 与 15 进行位与计算后,结果为 10 。
10 = 1 0 1 0
15 = 1 1 1 1
10 | 15 = 1 1 1 1
按照上节的表格计算后,发现 10 与 15 进行位或计算后,结果为 15 。
10 = 1 0 1 0
15 = 1 1 1 1
10 ^ 15 = 0 1 0 1
按照上节的表格计算后,发现 10 与 15 进行位异或计算后,结果为 5 。
10 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
~ 10 = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1
因为一个整数是由 4 个字节组成,每个字节是 8 位,因此
在 1010 前还有 28 个 0 存在。将这些 0 全部变为 1 ,这时的数字代表 -11。
15 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
~ 15 = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
在 1111 前还有 28 个 0 存在。将这些 0 全部变为 1 ,这时的数字代表 -40。
10 = 1 0 1 0
10 << 2 = 1 0 1 0 0 0
把 10 向左移动两位,右面的空余位置用 0 补齐。
Tips:请特别注意,在向左移位的过程中,如果左移的位数超出数据的存储最大位数,那么将产生错误。
下面的示例程序展示了这种错误。
# include <stdio.h>
int main()
{
int x,y,z;
x=10; // 10 = 1010
z=x<<200;
printf("x << 200 = %d\n", z);
return 0;
}
显然超过了 int 类型可以表示的最大位数。
在编译的时候,会出现如下的错误。
test.c: In function ‘main’:
test.c:7:8: warning: left shift count >= width of type [-Wshift-count-overflow]
z=x<<200;
15 = 1 1 1 1
15 >> 2 = 0 0 1 1
把 15 向右移动两位,左面的空位用 0 补齐。
位运算作为一种直接的,符合数字电路逻辑的运算,广泛的存在于我们的生活中。在编程语言中,通过位运算可以方便的获得如网络地址的计算,还有我们日常的一些加减乘除都是可以通过位运算来实现的。只不过很多运算由于表示不直观,容易出错,所以还是使用了普通的算数运算符等来进行计算。
同时也要区分,位运算与我们介绍的逻辑运算符很相似,所以请大家注意区分。