Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48973
  • 博文数量: 10
  • 博客积分: 229
  • 博客等级: 二等列兵
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-05 15:47
文章分类
文章存档

2012年(10)

我的朋友

分类:

2012-03-06 19:54:08

原文地址:Linux c中的位运算 作者:bill_cao

所谓的位运算指的是二进制位的运算。在系统软件中,常要处理二进制位的问题。例如,将一个存储单元中的二进制位左移或右移以为,两个数按位相加等等。

       C语言中提供了如表1所列出的位运算符。

1

运算符

含义

运算符

含义

&

按位与

~

取反

|

按位或

<< 

左移

^

按位异或

>> 

右移

       说明:

       1、位运算中除~以外,均为二目运算符,即要求两侧各有一个运算量。

       2、运算量只能是整型或字符型的数据,不能为实型数据。

下面对各个运算符做简单的介绍。

按位与运算符(&)

       参加运算的两个数据,按二进制位进行“与”运算。运算规则为:如果两个相应的位上的二进制为都为1,则该位的运算结果也为1,否则为0。即如下的表达式:

       0&0=0   0&1=0   1&0=0   1&1=1

       如果参加位运算的操作数为负数,则以补码的形式表示二进制数,然后按位进行与运算。

       按位与运算有一些特殊的用途如下:

       1、清零。

       如果想将一个单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合下面的条件:原来数中为1的位置,新数中相应的位为0,然后使二者进行与运算,既可以达到清零的母的。

       2、取一个数中某些指定的位。只要将要取的某些位与1相与,就可以得到想要取得位的值。

       3、将某一位留下来。要想将某一位留下来,就与一个数进行与运算,次数在该位取1。这一点在嵌入式开发中应用的比较广泛。例如,在点亮一个LED灯的时候,通过控制与之相连的处理器的IO口,取1或者取0 就可以控制LED灯的亮和灭。

按位或运算符( | )

       两个相应的二进制位中只要有一位为1,该位相或之后的结果就为1。规则如下:

              0|0=0   0|1=1   1|0=1   1|1=1

       或运算主要是用将一个数据的某些位置1

异或运算符(^)

       异或运算符^也成为XOR运算符。它的规则是:若参加运算的两个二进制位同号,则结果为0,异号则为1。即 0^0=00^1=11^0=11^1=0。异或的意思就是判断两个相应的位值是否为“异”,为“异”就为真,否则为假。

       我印象中异或运算的一个比较有意思的应用是交换两个值,不使用中间变量。

       假设a=3b=4,想交换ab的值,可以用下面的赋值语:

       a=a^b;

       b=b^a;

       a=a^b;

       上面的三个赋值语句就可以实现交换两个数的值。

       说明:

              1、执行前两个赋值语句:“a=a^bb=b^a”相当于b=b^(a^b)。而b^a^b等于a^b^b     b^b的结果为0,因为同一个数与本身相异或,结果必为0。因此,b的值就等于a^0,          其值为3

              2、再执行第三个赋值语句:a=a^b。由于a的值的等于(a^b)b的值等于(b^a^b)  因此,相当于a=a^b^b^a^b,即a的值等于b的值,即4

      

注:

       回顾我们所学过的,实现交换两个数的值的方法有4种。

取反运算符(~)

       ~是一个单目运算符,用来对一个二进制数按位取反,即将0变为1,将10。取反运算符的优先级比算术运算符,关系运算符,逻辑运算符和其他位运算符都要高。

左移运算符(<<)

       用来将一个数的各二进制位全部左移若干位。高位左移溢出后就舍弃。左移1 位相当于该数乘以2,左移两位就相当于乘以2的平方,依次类推,左移多少位就相当于该数乘以2的多少次方,但是此结论只适用于该数左移时被溢出舍弃的高位中不含1的情况。

右移运算符(>>)

       用于将一个数的各二进制位全部右移若干位,移到右端的低位被舍弃,对去符号数,高位补0.右移以为相当于除以2,右移n位相当于除以2n次方。在右移的过程中,需要注意符号位的问题。对于无符号数,右移时左边高位补0,对于有符号的值,如果原来符号位为0,则左边也是一如0;如果符号位为1,,则左边移入的是1还是0,要取决于所用的计算机系统。移入0的称为“逻辑右移”,移入1的称为“算术右移”。

补充知识:位段

       位段以位为单位定义的结构体中成员所占用存储空间的长度,含有位段的结构体类型称为位段结构。位段结构也是一种结构体类型,只不过其中含有以位为单位定义存储长度的整数类型位段成员。采用位段结构既节省存储空间,又可方便操作。

       位段结构中位段的定义格式为: unsigned  <成员名> : <二进制位数>

       例:

       struct bytedata
       {

              unsigned a:2;   /*位段a2*/
              unsigned:6;  /*
无名位段6但不能访问*/
              unsigned:0;     /*
无名位段0表下一位段从下一字边界开始*/
              unsigned b:10;  /*
位段b10*/
              int i;          /*
成员i从下一字边界开始*/
       }data;

       位段数据的引用:同结构体成员的数据引用一样,但是应该注意位段的最大值范围不要超过二进制位数定的范围,否则超出部分会丢弃。例如:data.a=2;但是data.a=10;就超出了范围。

       关于位段数据,注意以下几点:

       1)一个位段必须存储在同一存储单元(即字)之中,不能跨两个单元。如果其单元空间不够,则剩余空间不用,从下一个单元起存放该位段。
      
2)可以通过定义长度为0的位段的方式使下一位段从下一存储单元开始。
      
3)可以定义无名位段。
      
4)位段的长度不能大于存储单元的长度。
      
5)位段无地址,不能对位段进行取地址运算。
      
6)位段可以以%d%o%x格式输出。
      
7)位段若出现在表达式中,将被系统自动转换成整数。

    结构体大小原则:由于存储变量时地址对齐的要求,编译器在编译程序时会遵循两条原则:第一、结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)。第二、结构体大小必须是所有成员大小的整数倍。

 

阅读(840) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~