位运算就是将对应的数值转化为二进制然后按位进行相应的运算。(好吧,这个概念是我自己的理解...)
下面的叙述指示结合个人的经历与理解,肯定是不够全面、甚至不够准确的,只是希望抛砖引玉,同时也作为自己对位运算这一块的一个简单总结。
位运算主要包括:位与(&)、位或(|)、位取反(~)、位异或(^)、左移(<<)、右移(>>)六种下面分别介绍。
1 #include <stdio.h> 2 3 void main() 4 { 5 unsigned char a = 0xBD; /* a的二进制表示为 1011 1101 */ 6 unsigned char b = 0x46; /* b的二进制表示为 0100 0110 */ 7 8 unsigned char c = a & b; /* c的二进制表示为 0000 0100 */ 9 unsigned char d = a | b; /* d的二进制表示为 1111 1111 */ 10 unsigned char e = a ^ b; /* e的二进制表示为 1111 1011 */ 11 unsigned char f = ~a; /* f的二进制表示为 0100 0010 */ 12 unsigned char g = a << 3; /* g的二进制表示为 1110 1000 */ 13 unsigned char h = b >> 3; /* h的二进制表示为 0000 1000 */ 14 15 printf("c = 0x%02x\n",c); 16 printf("d = 0x%02x\n",d); 17 printf("e = 0x%02x\n",e); 18 printf("f = 0x%02x\n",f); 19 printf("g = 0x%02x\n",g); 20 printf("h = 0x%02x\n",h); 21 }
运行结果。
1. 位与(&).
这个和逻辑运算符 与(&&) 是不是长得像?他们的功能也异曲同工!运算的两位同时为1时结果为1,否则为0.如上例,a、b位与得c,具体计算过程为
2. 位或(|)
这个和逻辑运算符 或(||) 异曲同工,运算的两位有一位为1则结果就为1,只有当二位同时为0时结果为0.如上例a、b位或得d,计算过程参见上图吧。
3. 位取反(~)
这个和逻辑运算符 非(!) 异曲同工,单目运算符,将每一位都取反,如 ~(1101) 为 0010,就是这个意思。
4. 位异或(^)
双目运算符,两个数异或,位值相同则异或结果为 0 ,位值不同,则异或结果为 1.
5. 左移运算(<<)
将数按二进制位向左移动指定位数,右边补0.比如 unsigned char x = 1010 1101(这个表示不规范,当成伪代码看吧),则x<<3 结果为 0110 1000,相当于原数乘以2的3次方。
6. 右移运算(>>)
将数按二进制位向右移动指定位数,左边补0.比如 unsigned char x = 1010 1101(这个表示不规范,当成伪代码看吧),则x>>3 结果为 0001 0101,相当于原数除以2的3次方。
.
.
.
以上介绍的就是C语言中的位运算,个人感觉其核心就是要把握住所有的操作都是针对二进制位进行的!
可能会有同学们问了,这些位运算有啥用啊?下面结合我个人经历简介一下这些位运算在对硬件编程操作中的使用。
.
*********************************** 分割线 ***************************************
.
1. 对某位写0
我个人使用这个比较多的是IO操作,比如需要对IO某位写0.比如 IO 地址是16位的 0xAB36 ,需要将第四位(从右边数)置为0,这个时候怎么办呢,我们的 位与 运算就有用了:
unsigned char addr = 0xAB36 ; write( (addr & 0xFFF7) , 0 ); /*伪代码*/
2. 对某位写1
还以 IO 为例 ,需要将第四位(从右边数)置为1,这个时候需要用到 位或 运算
unsigned char addr = 0xAB36 ; write( (addr | 0x0008) , 1 ); /*伪代码*/
3. 对某位取反
这个就是说,这个位当前值如果为0则把它改写为1 ,如果当前值为1则把它改写为0 ,这个要用到 异或 运算
unsigned char addr = 0xAB36 ; write( addr ^ 0x0008 ); /*伪代码*/
这个稍微有点绕啊,你就这样想,若原位值为1,则对0异或得1,对1异或得0 ; 若原位值为0,则对0异或得0,对1异或得1.看到了吧,对0异或得原值,对1异或得反值!
4. 获得某位的当前值(判断当前值为0或1)
这个也要用到位与和一个if判断,例如还是判断第四位值是否为1:
if( 0xAB36 & 0x0008 ) /*当前位值为1*/ { ... }
这个好理解吧,你把其他为都置为0,第四位置为1,这就是0x0008,如果原数(0xAB36)第四位为1,则这个 位与 后的数就不为0了。
5. 组合值
unsigned char a = 0xAB; unsigned char b = 0xCD; unsigned short c = a<<8 | b; /* c= 0xABCD */
6. 拆分值
unsigned short a = 0xABCD; unsigned char b = a>>8 & 0xFF; /* b= 0xAB */
这些运算关键就是要注意数据类型憋搞错了。
.
.
.
位运算还有很多,大家要触类旁通。
*********************++++++++++++++++++++**********************++++++++++++++++++++
2016年10月3日补充:
7.求某数的二进制形式包含多少个 1
int func(int num) { int count = 0; while(num) { num = num & (num - 1); /* 这句话是关键 */ count ++; } return count; }