一,位操作一般用法
1,特定位清零用“&”。
要想把一个数的特定位清零,就需要构造另一个数,这个数的对应特定位为0,其他位为1。2
2,特定位置1用“|”。
要想把一个数的特定位置1(设置特定位),就需要构造另一个数,这个数的对应特定位为1,其他位为0。
3,特定位取反用“^”。
要想把一个数的特定位取反,就需要构造另一个数,这个数的对应特定位为1,其他位为0。
二,如何构造“另一个数”。
1,如果这个数比较少位为“1”,大部分为“0”,则可以通过连续多“1”左移n位得到。
2,如果这个数比较少位为“0”,大部分为“1”,则可以先通过构建其位反数,然后再位取反来得到。
3,如果想要构造的数中连续1(连续0)的部分不止一个,那么可以通过多段分别构造,然后再彼此位或即可。
三,位运算实战。
1,给定一个整数型a,设置a的bit3,同时保证其他位不变。
a |= (0x1<<3);
2,给定一个整数型a,设置a的bit3~bit7,同时保证其他位不变。
a |= (0x1f<<3);
3,给定一个整数型a,清除a的bit15,同时保证其他位不变。
a &= (~(0x1<<15));
4,给定一个整数型a,清除a的bit15~bit23,同时保证其他位不变。
a &= (~(0x1ff<<15));
5,给出一个整数型a,取出bit3~bit8。
第一步:先把bit3~bit8保持不变,其他位清零。
a &= ((0x3f<<3)) ;
第二步:再将其右移3位得到结果。
a>>3;
6,给一个寄存器的bit7~bit17赋值937(其他位不受影响)。
关键点:第一,不能影响其他位,第二,并不知道bit7-bit17中原来的值。
第一步:对于关键点二,得先把bit7~bit17清零。
a &= (~(0x7ff<<7));
第二步:将937写到对应位。
a |= (937<<7);
7,将一个寄存器的bit7~bit17的值加17(其他位不受影响)。
第一步:先读出对应位的数。
data = (a & (0x7ff<<7))>>7;
第二步:data += 17;
第三步:对应位清零。
a &= (~(0x7ff<<7));
第四步: a |= (data<<7);
8,给一个寄存器的bit7~bit17赋值937,给一个寄存器的bit21~bit25赋值17(其他位不受影响)。
两次第6题。
a &= (~(0x7ff<<7) | ~(0x1f<<21));
a |= ((937<<7) | (17<<21))
9,宏实现置位,复位。(一般笔试题中规定的是最右边为第一位)
#define SET_BIT(x,n) (x|((1U)<<(n-1)))
#define CLEAR_BIT(x,n) ((x & ~((1U)<<(n-1))))
10,截取变量的部分连续位。比如变量0x88,即0x10001000b,若截取第2~4位,则值为100b = 4。
#define GETBITS(x,n,m) ((x & ~(~(0U)<<(m-n+1))<<(n-1))>>(n-1))
分析:
#define GETBITS(x,n,m) ((x & ~(~(0U)<<(m-n+1)) <<(n-1)) >>(n-1))
第一次分解:
(x & ~(~(0U)<<(m-n+1)) <<(n-1)) >> (n-1))
第二次分解:
x & ~(~(0U)<<(m-n+1)) <<(n-1)
第三次分解:
~(~(0U)<<(m-n+1)) << (n-1)
~(~(0U)<<(m-n+1)):得到连续(m-n+1)个1的数 。
~(~(0U)<<(m-n+1)) << (n-1):将连续(m-n+1)个1的数 移动到对应连续位处。
(x & ~(~(0U)<<(m-n+1)) <<(n-1)):取出对应位处的位值。
(x & ~(~(0U)<<(m-n+1)) <<(n-1)) >> (n-1)):得到所求连续位的值。
#include <stdio.h> #define GETBITS(x,n,m) ((x&(~(~(0u)<<(m-n+1))<<(n-1)))>>(n-1)) #define CLEARBITS(x,n,m) (x&(~((~(~(0u)<<(m-n+1)))<<(n-1)))) #define SETBITS(x,n,m) (x|(~(~(0u)<<(m-n+1)))<<(n-1)) int main() { int a = 0x88; printf(" %d ",GETBITS(a,2,4)); //4 a = 0xff; printf(" 0x%x ",CLEARBITS(a,2,4)); // 0xf1 a = 0xf1; printf(" 0x%x ",SETBITS(a,2,4)); //0xff }