位运算: 0XF => 1111 0XF0 => 1111 0000 0X0F0F=0XF0F => 1111 0000 1111
&(与): C语言中清0某些位的操作
0x12345678 (通过用0来&操作 实现清零)
& 0xFFFF000F
------------------------
0X12340008
|(或): C语言中的置1操作
0x12345678 0101 0110
| 0XFF00 1111 1111
------------------------
0X1234FF78 1111 1111
^(异或): C语言中取反操作 相同为0 不同为1 (记忆方法: 相异的两个数取或运算 则等于1 相同的两个数自然能想到是相同则清零)
0x12345678 0110
^ 0xF00 1111
---------------------
0X12345978 1001
实例使用:( 获取特定数为1 )
0xf8 ==> 1111_1000 把第3位到第7位 置1 可以用这种操作方法
从哪一位开始置1 则移动多少位 这里是左移
3到7 总共有5位 1_1111 = 0x1f
结果为: 0x1f << 3 = 1111_1000 = 0xf8
同理:
把第3到第7和第23到25位同时置1
((0x1f <<3) | (0x7<<23)) = 0x380_00f8
实例使用:( 获取特定数为0 )
方法: 按照上例 先把特定位置1 再按位取反
例:把bit4~bit10 取0 其余位为1
~(0x7f <<4) = 0xfffff80f
总结:
1.如果你想要的这个数比较少位为1,大部分位为0,则可以通过连续很多个1左移n位得到.
2.如果你想要的数是比较少位为0,大部分位为1,则可以通过先构建其位的相反数,然后再位取反来得到.
3.如果你想要的数中连续1(连续0) 的部分不止1个,那么可以通过多段分别构造,然后再彼此位或即可.这时候因为参与或运算的各个数为1的位是不重复的,所以这时候的位或其实相当于几个数的叠加.
位运算的实战演练
置1用 | , 清零用 & , 取反用 ^ , ~和<< >> 用来构建特定的二进制数
1.给定一个整型数a,设置a的bit3,并保证其他位不变.
a = a | (1<<3) 或者 a |= (1<<3)
2.给定一个整型数a,设置a的bit3~bit7,并保证其他位不变.
a = a | (0b11111 <<3) 或者 a = a | (0x1f << 3)
3.给定一个整型数a,清除a的bit15,并保证其他位不变.
a = a & (~(1 << 15)) 或者 a &= (~(a << 15))
4.给定一个整型数a,清除a的bit15~bit23,并保证其他位不变.
a = a & (~(0b111111111 << 15)) 或者 a &= (~(0b111111111 << 15))
a = a & (~(0x1ff << 15)) 或者 a &= (~(0x1ff << 15))
5.给定一个整型数a,取出a的bit3~bit8.
第一步: 先将这个数bit3~bit8不变,其余位清零.
第二步: 再将其右移3位得到结果.
a = ffff_ffff;
a &= (0x3f << 3); //0x3f => 11_1111 << 3 = 1_1111_1000
a >> 3; //结果为 0x1f8
6.用C语言给一个寄存器的bit7~bit17赋值937(其余位不受影响).
关键点: 第一, 不能影响其他位; 第二, 你并不知道原来bit7~bit17中装的值.
思路: 第一步, 先将bit7~bit17全部清零,不能影响其他位.
第二步,再将937写入bit7~bit17中,不能影响其他位. 17-7+1 = 11 (11个1)
a &= ~(0x7FF << 7); //bit7~bit17全部清零 0x7ff = 111_1111_1111
a |= (937 << 7); //将937写入bit7~bit17中
7.用C语言给一个寄存器的bit7~bit17中的值加17(其余位不受影响).
第一步: 先读出原来bit7~bit17的值
unsigned int tem;
unsigned int a = 0xc30288f8;
tem = a & (0x7ff << 7);
tem >>= 7;
第二步: 给这个值加17
tem += 17;
第三步:将a的bit7~bit17清零
a &= ~(0x7ff << 7);
第四步:将第二步算出来的值写入bit7~bit17中
a |= tem;
8.用C语言给一个寄存器的bit7~bit17赋值937,同时给bit21~bit25赋值17(其余位不受影响).
解法1: 两次第6题解法
a = 0xc30288f8
//bit7~bit17赋值937
a &= ~(0x7ff << 7);
a |= 937 << 7;
//bit21~bit25赋值17
a &= ~(0x1f << 21);
a |= 17 << 21;
解法2: 合二为一
a &= ~((0x7ff << 7) | (0x1f << 21));
a |= ((937 << 7) | (17 << 21));
用宏定义来完成为运算:
置位:置1 复位:清零
(用宏定义将32位数的第n位(右边起算,也就是bit0算第1位)置位)
1.直接用宏来置位 , 复位 (最右边为第一位)
#define SET_BIT_N(x,n) (x | (1U << (n-1))) //这里U是无符号数的意思
//n-1是因为从bit0开始 这里的n是32位的要-1 0~31
(用宏定义将32位数的第n位(右边起算,也就是bit0算第1位)复位)
2.直接用宏来复位 , 复位 (最右边为第一位)
#define CLEAR_BIT_N(x,n) (x & ~(1U << (n-1))) //这里U是无符号数的意思
//n-1是因为从bit0开始 这里的n是32位的要-1 0~31
3.(用宏定义将32位数的第n位到第m位(右边起算,也就是bit0算第1位,m为高位)置位)
分析: 假如n = 3,m=6, 题目就是把bit2到bit5置位
我们需要一个算式来得到(m-n+1) 个1
算法: 第一步: 先得到32位1: ~0U //对一个无符号0取反 得到32位1
第二步: 将第一步得到的数右移32-(m-n+1)位 即可得到(m-n+1)个1 ==>(~0U) >> (32-(m-n+1))
(有个缺陷 就是只能在32位以内使用) 改进: == > ~((~0U) << (m-n+1))<<(n-1)
优势: 通用 64位(或更高位运算)照杀
#define SET_BIT_N_M(x,n,m) (x | (((~0U) >> (32-(m-n+1))) << (n-1)))
改进:
#define SET_BIT_N_M(x,n,m) ~((~0U) << (m-n+1))<<(n-1)
4.截取变量的连续位. 变量0x88 ==> 10001000b 截取第2~第4位 , 则结果为 : 100b = 4
#define GETBITS(x,n,m) (x & (~(~(0U) << (m-n+1)))<<(n-1)) >> (n-1))
分析复杂宏思路: 一:先分析由几部分组成: 2部分
x & (~(~(0U) << (m-n+1)))<<(n-1)) >> (n-1)
二:继续分析剩下的部分: 2部分
x & (~(~(0U) << (m-n+1)))<<(n-1))
三:通查C语言优先级表或自己写程序测试 优先顺序
(~(~(0U) << (m-n+1))) << (n-1)
int main(void){
//第一题
unsigned int a = 0xffffffff;
unsigned int b = 0;
b = SET_BIT_N(a,4);
//第二题
unsigned int a = 0xffffffff;
unsigned int b = 0;
b = CLEAR_BIT_N(a,4);
//第三题
unsigned int a = 0x0;
unsigned int b =0;
b = SET_BIT_N_M(a,1,4); //从第1位到第4位置1 即bit0~bit3 置1
//第四题
unsigned int a = 0x88;
unsigned int b =0;
b = GETBITS(a,2,4); //从第1位到第4位置1 即bit0~bit3 置1
}