读《C程序设计语言》笔记8

按位运算符的运用:

C语言中提供了6个位操作符。这些运算符只能作用于整型操作数,即只能作用于带符号或无符号的char、short、int与long类型:

&  |  ^   >>  <<   ~

1.按位与的运用:&

  提取特定位、清零其余位:
  例如:mask中要保留的位上为1,其他位为0,a=a0&mask

      判断int的奇偶(效率比%2高得多):
  例如:(a&1)==0则为偶数,反之为奇数。(原理:因为奇数二进制末位总为1,偶数总为0。原数与00…001进行按位与运算,就得到了a二进制末位的值。)

2.按位异或运用:^

  特定位取反
  例如:mask中要取反的位为1,其余为0,a=a0^mask

     不用中间变量交换两数的值
  例如:要交换a、b的值只需:a=a^b;b=a^b;a=a^b;即可。
  (原理:上式即a=(a^b)^(a^b)^b,b=a^b^b。由于一个数与它本身进行“按位异或”运算得到0,任何一个数与0进行“按位异或”运算得到它本身,故上式即是:a=[b的原值],b=[a的原值]。这样就达到了交换a、b的目的。)

下面用一个函数来说明位运算符的操作:

getbits(x, p, n);它返回x中从右边数第p位开始向右数n位的字段。这里假定最右边的一位是第0位,n与p都是合理的正值。

例如:getbits(x, 4, 3)返回x中的第4、3、2三位的值。

/**********
	Description:
		getbits函数:返回x中从第p位开始的n位
****************/
unsigned getbits(unsigned x, int p, int n)
{
	return (x >> (p+1-n)) & ~(~0 << n);
}

其中,表达式(x >> (p+1-n))将期望获得的字段移位到字的最右端。

  ~0的所有位都为1,这里使用语句~0 << n将~0左移n为,并将最右边的n位用0填补。

  再使用~运算对它按位取反,这样就建立了最右边n位全为1的屏蔽码。

习题2-6。

  编写一个函数setbits(x, p, n ,y),该函数返回对x执行下列操作后的结果值:将x中从第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变。

/*************************
Description:
	setbits:set n bits of x at position p with bits of y
*************************/
unsigned setbits(unsigned x, int p, int n, unsigned y)
{
	return x & ~(~(~0 << n) << (p+1-n)) | (y & ~(~0 << n))<<(p+1-n);
}

分析:

为了把x中的n位设置为y最右边的n位的值
  xxx...xnnnx...xxx  x
  yyy..........ynnn  y
我们需要对x中的n位清零;把y中除最右边的n位以外的其他位都清零并左移到第p位处;然后对前面两步的结果值进行OR操作。如下所示:
  xxx...x000x...xxx
  000...0nnn0...000  OR操作
  -----------------
  xxx...xnnnx...xxx

为了对x中的n位清零,我们需要把x与一个屏蔽码进行AND操作。这个屏蔽码从位置p开始的n位都是0,其他位则全是1。
首先,把一个所有位都为1的屏蔽码左移n位,在它的最右边制造出n位0:
   ~0 << n
然后,把屏蔽码最右边的n位设置为1,把其余位全部设置为0:
   ~(~0 << n)
接下来,把屏蔽码最右边的n个1的位左移到第p位处:
   ~(~0 << n) << (p+1-n)
再往后,把屏蔽码从第p位开始的n位设置为0,把其余位全部设置为1
   ~(~(~0 << n) << (p+1-n))
用这个屏蔽码和x进行AND操作,就完成了对x从第p位开始的n位清零的工作。
   x & ~(~(~0 << n) << (p+1-n));
为了把y中除最右端的n位以外的所有位清零,我们需要用最右端的n位全为1,其余位全为0的屏蔽码对y进行AND操作,如下所示:
   ~(~0 << n)
用这个屏蔽码和y进行AND操作,我们就选出了y最右端的n位。具体操作如下:
   y & ~(~0 << n)
接下来,我们还需要用下面的操作把这n位左移到位置p处:
   (y & ~(~0 << n)) << (p+1-n)

最后,对通过上述步骤得到的两个阶段性的结果进行OR操作:就完成了“将x中从第p位开始的n位设置为y中最右边n位的值,x的其余位保持不变”。

一个巧妙运用移位运算符的程序:(感觉面试中也经常出这样的题目)

输出int类型值中1的个数,或者用二进制表示出来;

#include<iostream>
using namespace std;
int main()
{
	int a=13;
	int s=0;
	for(int i=1;i<=32;a<<=1,i++) 
	{	
		if(a<0)
			s++;
        cout<<(a<0);
	}
	cout<<endl<<"1的个数为:"<<s<<" 个"<<endl;
	system("pause");
	return 0;
}

执行结果:

  

  声明int型变量时,默认的为signed,带符号位,所以可以这样应用。

  循环32次才统计出多少个1来,如果仅仅是统计1的个数,效率就不算高了,《编程之美》上有同样的面试题目,给出了比较高效的算法,《C程序设计语言》里也有更高效的算法,后面再补上来,自己电脑遭人攻击,挂了,相当郁闷。

  intshortlong类型默认均为带符号型的

原文地址:https://www.cnblogs.com/wangzhiyu811/p/2104849.html