跳到主要内容

C 语言中的位运算符

在 C 语言中,相同的数字可以用不同的数制来表示。也就是十进制的数字可以等价的表示为二进制或者十六进制。那么对于二进制来说,可以进行逐个数字之间,也就是每一个数字位的运算。这种运算也广泛的存在我们日程使用的数字电路中。其实计算机的运算原理最底层就是位运算,也就是 0 和 1 的运算。

1. 位运算符

运算符作用示例
&位与a&b
位或
^位异或a^b
~位非~b
<<位左移a<<b
>>位右移a>>b

对于位运算中的与、或、异或可以通过下面的表格来阐明。

xyx & yxy
00000
01011
10011
11110

对于非操作符有下表的结果。

x~x
01
10

移位操作就是将位向左或者向右移动,空位用 0 来补齐。

2. 示例

# 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 补齐。

3. 小结

位运算作为一种直接的,符合数字电路逻辑的运算,广泛的存在于我们的生活中。在编程语言中,通过位运算可以方便的获得如网络地址的计算,还有我们日常的一些加减乘除都是可以通过位运算来实现的。只不过很多运算由于表示不直观,容易出错,所以还是使用了普通的算数运算符等来进行计算。

同时也要区分,位运算与我们介绍的逻辑运算符很相似,所以请大家注意区分。