按位异或:相同为0,不同为1。
A xor A = 0;
A xor 1 = not A;
A xor 0 = A;
由1、3组合可知,任何数异或同一个数2次等于其本身,利用这点可对两个数进行交换,如:
int nNum1=1,nNum2=2;
nNum1 = nNum1 ^ nNum2;
nNum2 = nNum1 ^ nNum2; // = nNum1^nNum2^nNum2,就=nNum1
nNum1 = nNum1 ^ nNum2; // 此时nNum2的已等于nNum1,
// 所以 = nNum1^nNum2^nNum1,结果等于nNum2
两个数互相交换通过如此或异就完成了,不过在如今的年代,为了节省一个中间变量那么几字节的内存而使代码可读性变差,得不偿失,况且异或用在变量交换这种小事上也是大材小用了,扩展点想,利用异或的特性,备份一段数据只需其一半的容量空间就够了,前后一半相异或保存,只要有一半数据就能得到另一半数据。
异或主要的几个用途:
1、 清0。
2、 交换两数。
3、 备份数据(只占一半空间)。
4、 局部取反。
C语言中的位移都是算术位移,算术左移同逻辑左移一样都是高位丢弃,低位补0。区别在右移上,算术右移无符号数同逻辑右移一样低位丢弃,高位补0;但如果算术右移一个有符号数,那么它将低位丢弃,高位补符号位(也就是右移负数时,算术右移与逻辑右移的结果会不同)。
算术左移等同于乘以2的幂,算术右移正数时等于除以2的幂,当右移一个负数时,想得到正确结果先要加上2的幂-1再右移,否则当右移不能整除时,不会得到正确的结果。
用位运算求绝对值(无判断分支)
int NewAbs(int n) {
int nSign = n >> 31; // nSign=0(n为正数)或0xFFFFFFFF(n为负数)
int nRet = n ^ nSign; // 对于正数nRet=n,对于负数nRet=~n
return nRet-nSign; // 对于正数返回n本身,对于负数求补(取反加1)后返回,也就是它的正数值。
}
位段:
用关键字struct包裹,定义位段 类型 位段名:数字(表占几位)。位段的占位是从低位算起,如果定义时没有位段名表只占位数(不引用),如果既没有位段名且占位数字为0则表示放弃本字节单位,下一个位段将在新的对齐字节单位开始。
对一个位段成员赋值大于成员的位数,取此赋值数的低位段数。