位操作符详解

几种位操作符

<<   ——左移

>>   ——右移

&   与——相同位都为1,操作结果才位1

|    或——相同位只要有1,操作结果就为1

~   非——取反操作

^   异或——对应位不相同时,操作结果为1

简单应用

1.  <<  >>

//为正数时
	int a = 10;              
	int v = a >> 2;          
	printf("v=%d\n", v);     //v=2

	int z = a << 2;         
	printf("z=%d\n", z);     //z=40   

 右移一位=a÷2;左移一位=ax2

因此,右移n位之后的值为 a÷2^n

左移n位之后的值为 a x 2^n

//为负数时
	int b = -10;            
	int w = b >> 2;         
	printf("w=%d\n", w);     

	int r = b << 28;
	printf("r=%d\n", r);     //左移 右边补0,负数左移有可能会变成正数

结果为

w=-3
r=1610612736

//移动负数位 (两个数的绝对值相加=该类型的位数)
	//右移
	int c = 10;               //int 只有32位(4x8)  0-31为一个循环
	int m = c >> 32;          //m=c=10;移动32位回到自身
	int d = c >> 31;          
	int q = c >> -1;          //右移-1位相当于右移了31位
      
	printf("q=%d\n", q);      //q=0
	printf("d=%d\n", d);      //d=0
	//左移
	int n = c << -28;         //左移-28位相当于左移4位
	int h = c << 4;
	printf("n=%d\n", n);      //n=160
	printf("h=%d\n", h);      //h=160

2. ^ 异或的简单操作

不创建临时变量,实现两个数的交换

    int a = 10;
    int b = 20;
//第一种方法  有缺陷,当数值太大时,可能会超出int的范围
	printf("a=%d,b=%d\n", a, b);
	a = a + b;  //30
	b = a - b;  //10
	a = a - b;  //20
	printf("a=%d,b=%d\n", a, b);

	//第二种方法  用异或 ^  相同为0,不同为1
	a = a^b;     
	b = a^b;     
	a = a^b;     
	printf("a=%d,b=%d\n", a, b);

      10    0000 0000 0000 0000 0000 0000 0000 1010       a
                                                          ^
      20    0000 0000 0000 0000 0000 0000 0001 0100       b
________________________________________________________  
            0000 0000 0000 0000 0000 0000 0001 1110      // a=a^b=30
                                                          ^
      20    0000 0000 0000 0000 0000 0000 0001 0100       b
________________________________________________________  
            0000 0000 0000 0000 0000 0000 0000 1010      // b=30^20=10
                                                          ^
            0000 0000 0000 0000 0000 0000 0001 1110       30
________________________________________________________
            0000 0000 0000 0000 0000 0000 0001 0100       a=10^30=20

            

3.&的简单用法

求一个数存储在内存中的二进制中1的个数

//方法一:一个位一个位判断 效率低
unsigned char a = 56;  //0011 1000
	int count = 0;
	
	for (int i = 0; i < 8; ++i){    //char只有8个比特位
		if (a & 0x01){
			count++;
		}
		a >>= 1;
	}
	printf("count=%d\n", count);
//方法二:不用循环8次,当没有1时,循环结束
	while (a){
		count += (a & 0x01);
		a >>= 1;
	}
	printf("count=%d\n",count);


//算数运算
    while (a){               //当a=0时 循环结束
		if (a % 2 == 1)       //说明当前位为1
			count++;
		a /= 2;         //每次都除2,相当于右移一位
		//a >>= 1;       //位运算效率比算数运算高一点
	}
	printf("count=%d\n", count);

 

方法二本质上与方法一是一样的,只是改变了循环条件,不用循环8次,当最后一个1检测完毕后,a变为0,退出循环。本例中,方法二执行6次。

上述三个写法,本质上是一样的,只是在效率上稍有不同。

//方法三:
while (a){
		a &= (a - 1);
		count++;
	}
	printf("count=%d\n", count);



//效率高,只与1的个数有关  每&一次消除一个1
//  0100 1101     a
//  0100 1100     a-1   a&(a-1)=0100 1100
//---------------
//  0100 1100     a
//  0100 1011     a-1   a&(a-1)=0100 1000
//---------------
//  0100 1000     a
//  0100 0111     a-1   a&(a-1)=0100 0000
//---------------
//  0100 0000     a
//  0011 1111     a-1   a&(a-1)=0000 0000
//---------------
//  0000 0000           到0循环结束

4.& | ~  的简单应用

一道面试题:

实现对一个8 bit 数据(unsigned char 类型)的指定位的置0或者置1操作,并保持其他位不变
p_data 是指定的源数据,position是指定位(取值范围1~8) flag表示置0 置1操作,true:置1 false:置0.

思路:将1100 1000 中的第3位 置1时 只需将源数据与0000 0100相或即可
  1100 1000    
  0000 0100
------------------|
  1100 1100         其他位不改变

将1100 1000中的第4位 置0时 只需将源数据与1111 1011相与即可(即&  ~0000 0100)
  1100 1000
  1111 1011
------------------&
  1100 1000

void bit_set1(unsigned char*p_data, unsigned char position, bool flag){
	if (flag){
		//置1
		switch (position){
		case 1:
			*p_data |= 0x01;
			break;
		case 2:
			*p_data |= 0x02;
			break;
		case 3:
			*p_data |= 0x04;
			break;
		case 4:
			*p_data |= 0x08;
			break;
		case 5:
			*p_data |= 0x10;
			break;
		case 6:
			*p_data |= 0x20;
			break;
		case 7:
			*p_data |= 0x40;
			break;
		case 8:
			*p_data |= 0x80;
			break;
		default:
			break;
		}
	}
	else{
		//置0
		switch (position){
		case 1:
			*p_data &= ~0x01;
			break;
		case 2:
			*p_data &= ~0x02;
			break;
		case 3:
			*p_data &= ~0x04;
			break;
		case 4:
			*p_data &= ~0x08;
			break;
		case 5:
			*p_data &= ~0x10;
			break;
		case 6:
			*p_data &= ~0x20;
			break;
		case 7:
			*p_data &= ~0x40;
			break;
		case 8:
			*p_data &= ~0x80;
			break;
		default:
			break;
		}
	}
}
//简洁版
void bit_set2(unsigned char*p_data, unsigned char position, bool flag){
	if (flag)
		//置1
		*p_data |= (0x01 << (position - 1));
	else
		//置0
		*p_data &= ~(0x01 << (position - 1));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值