1、算术位运算
与 | 或 | 非 | 异或 |
& | | | ~ | ^ |
0x3F 3F 3F 3F是一个很有用的数值,是满足以下两个条件的最大整数:
①整数的两倍不超过0x7F FF FF FF ,即int的最大正整数
②整数的的每8位(每个字节)都是相同的
在程序设计中用memset(a,val,sizeof(a))初始化一个int数组a,该语句把数值val(0x00~0xFF)填充到数组a的每隔字节上,而1个int占用4个字节,因此用memset只能赋值出“每8位都相同”的int,0x7F 7F 7F 7F是用memset语句能初始化出的最大数值。
为避免加法算术上溢或繁琐的判断,我们经常用memset(a,0x3f,sizeof(a))给数组赋0x3F 3F 3F 3F的值来代替
2、移位运算符
①左移:在二进制表示下把数字同时向左移动,低位以0填充,高位越界后舍弃
1<<n=2n , n<<1=2n
②右移
n>>1=(n/2)
1)算术右移:在二进制补码表示下把数字同时向右移动,最高位以符号位填充,其他空缺位以0填充,低位越界后舍弃
2)逻辑右移:在二进制补码表示下把数字同时向右移动,空缺位以0填充,低位越界后舍弃
3、位运算符的优先级
1 | ~ |
2 | <<、>> |
3 | & |
4 | ^ |
5 | | |
6 | &=、^=、|=、<<=、>>= |
C语言运算符优先级
4、常见的二进制位变换操作
功能 | 位操作 |
取出第k位 | (x>>k)&1 |
取出第0~k-1位(末k位) | ((1<<k)-1)&x |
第k位取反 | (1<<k)^x |
第k位赋值1 | (1<<k)|x |
第k位赋值0 | (~(1<<k))&x |
去掉最后一位 | x>>1 |
在最后加一个0 | x<<1 |
在最后加一个1 | (x<<1)+1 |
把最后一位变成1 | x|1 |
把最后一位变成0 | (x|1)-1 |
最后一位取反 | x^1 |
把末k位变成1 | ((1<<k)-1)|x |
末k位取反 | ((1<<k)-1)^x |
去掉整数最右边的1 | (x-1)&x |
把右边连续1变成0 | (x+1)&x |
把右边第一个0变成1 |
(x+1)|x |
把右边连续的0变成1 |
(x-1)|x |
去掉右起第一个1的左边 | ((x-1)^x)&x |
5、位运算的运用
1)任何一个数和0异或是它本身,和自身异或为0
a^0=a, a^a=0;
故可用两数异或来交换数值
void swap(int *a,int *b) { *a=*a^*b; *b=*a^*b; *a=*a^*b; }
2)将整数的第n位清零
#define BITN (1<<n) 置位:a|=BITN; 清零:a&=~BITN;
3)清除整数最右边的1: x & (x-1)
如何判断整数x的二进制数中含有多少个1?
方法:
int func(int x) { int countx=0; while(x) { count++; x=x&(x-1); }
return countx;
}
方法二:
int func(int x) { int countx =0; while(x) { count+=x&1; x>>1; }
return countx;
}
4)求二进制中0的个数: x | (x+1)
int func(int x) { int countx=0; while(x+1) { countx++; x=x|(x+1); } return countx; }
5)判断奇偶
(x&1)==1
6)判断一个数是不是2的幂
n > 0 ? (n & (n-1)) == 0 : false ;
6、参考链接:
位运算与应用:https://blog.csdn.net/u012713968/article/details/50481680
优秀程序员不得不知道的20个位运算技巧:https://blog.csdn.net/zmazon/article/details/8262185
原文:https://www.cnblogs.com/lalala-lueluelue/p/12951662.html