• 读《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类型默认均为带符号型的

  • 相关阅读:
    sublime 安装 插件 package control,安装docblockr
    常用PHP方法个人汇总
    Linux使用SVN 钩子自动同步更新网站代码
    PHP处理微信支付回调
    nodejs v4.4.5在windows下的安装
    jQuery延迟执行的方法,常用于TAB效果和各种切换效果
    textarea提示还能输入多少字
    有关git的记录
    异常的处理,异常日志的规约
    poi导入导出
  • 原文地址:https://www.cnblogs.com/wangzhiyu811/p/2104849.html
Copyright © 2020-2023  润新知