您的位置: 网站首页 > 程序开发 > C语言程序设计 > 第2章 基本数据类型及运算符 > 【2.7 位 运 算】

2.7 位 运 算

 

2.7     

C语言和其他高级语言不同的是它完全支持按位运算符。这与汇编语言的位操作有些相似。表2-4列举了一些位运算符。

2-4  C语言中的位运算符

   

   

   

   

   

   

~

按位求反

5(高)

&

按位与

3

<< 

左移

4

^

按位异或

2

>> 

右移

4

|

按位或

1(低)

以上位运算符中除“~”以外,均为二目运算符,即要求两侧各有一个运算对象。

1.“按位求反”运算(~

~”是一个单目运算符,用来对一个二进制数按位求反,即将0110。例如,~025是对八进制数25(即二进制数00010101)按位求反。

~  0000000000010101

-----------------------------

    1111111111101010

即八进制数177752。因此,~025的值为八进制数177752,并非-025

2.“左移”运算(<<

“左移”运算符是双目运算符,用来将一个数的各二进位全部左移若干位。运算符左边是移位对象,右边是整型表达式,代表左移的位数。左移时,右端(低位)补0,左端(高位)移出的部分舍弃。例如:

int a=025;

a=a<<2;

a的二进制数左移2位,右补0

<<20000000000010101

-----------------------------

    0000000001010100

即八进制数54。因此,025<<2的值为八进制数54

3.“右移”运算(>>

“右移”运算符的使用方法与左移运算符一样,所不同的是移位方向相反。右移时,右端(低位)移出的二进制数舍弃,左端(高位)移入的二进制数分两种情况:对于无符号整数和正整数,高位补0;对于负整数,高位补1

例如:

int a=025;

a=a>>2;

a的二进制数右移2位,由于a为正整数,左补0

>>20000000000010101

-----------------------------

         0000000000000101

即八进制数5。因此,025>>2的值为八进制数5

4.“按位与”运算(&

“按位与”运算的规则是:参加运算的两个数据,按二进位进行“与”运算,如果两个相应的二进位都为1,则该位的结果值为1,否则为0。即:

0&0=00&l=01&0=01&1=1

例如:表达式12&10的运算如下。

  120000000000001100

& 10    0000000000001010

------------------------------------

   80000000000001000

即十进制数8。分析以上运算结果可知,按位与运算具有以下特征:任何位上的二进制数,只要和0进行与运算,该位即被屏蔽(清零);和1进行与运算,该位保留原值不变。利用这一特征可以实现如下功能。

1)清零。如果想将一个单元清零,也就是使其全部二进位为0,只需与0进行按位与运算,即可达到清零目的。

2)取一个数中某些指定位。如有一个整数a2个字节),想要其中的低字节,只需将a与八进制数3770000000011111111)按位与即可。如果想取2个字节中的高字节,只需将a与八进制数1774001111111100000000)按位与即可。

3要想将哪一位保留下来,就与一个数进行&运算,此数在该位取1,例如有一个数01010100(十进制数84),想把其中左面第34578位保留下来,设计一个数,其左面第34578位为1,其他位为0,即为十进制数59,将这两个数进行按位与运算即可。

5.“按位异或”运算(^

“按位异或”的运算规则是:参与运算的两个运算数中相对应的二进制位上同号,则结果为0,异号则为1。即:

0&0=00&1=11&0=11&1=0

例如,12^10

  120000000000001100

^ 10        0000000000001010

------------------------------------

   60000000000000110

即十进制数6。按位异或运算有如下应用。

1)使特定位翻转。假设有01111010,想使其低4位翻转,即1变为00变为1。可以将它与00001111进行按位异或运算,结果为01110101,结果值的低4位正好是原数低4位的翻转。要使哪几位翻转就将与其进行按位异或运算的该几位置为1即可。这是因为原数中值为1的位与1进行按位异或运算得0,原数中的位值01进行按位异或运算的结果得1

2)与0按位异或,保留原值。

3)交换两个值,不用临时变量。假设要想交换ab之值,可以用以下赋值语句实现:

a=a^b;

b=b^a;

a=a^b;

因为a=a^b,(假设ab最初的值加上下划线)则:

b=b^a=b^(a^b)=a^b^b=a^0=a

a=a^b=(a^b)^a=a^a^b=0^b=b

6.“按位或”运算(|

“按位或”运算的规则是:参加运算的两个数据,按二进位进行“或”运算,如果两个相应的二进位都为0,则该位的结果值为0,否则为1。即:

0|0=00|l=11|0=11|1=1

例如:表达式12|10的运算如下:

  120000000000001100

|  10   0000000000001010

------------------------------------

  140000000000001110

即十进制数14。分析以上运算结果可知,按位或运算具有以下特征:任何位上的二进制数,只要和1进行或运算,该位即为1;和0进行或运算,该位保留原值不变。例如,a是一个整数(16位),a=a|0377,使a的低8位全置为1,高8位保留原样。

7.位运算赋值运算符

位运算符与赋值运算符可以组成复合赋值运算符,这样的复合赋值运算符如表2-5所列。

2-5  复合赋值运算符

复合赋值运算符

   

等价的表达式

复合赋值运算符

   

等价的表达式

<<=

a<<=n

a=a<<n

^=

a^=b

a=a^b

>>=

a>>=n

a=a>>n

|=

a|=b

a=a|b

&=

a&=b

a=a&b

 

 

 

8.不同长度的数据进行位运算

位运算的运算数可以是整型和字符型数据。如果两个运算数类型不同时位数亦会不同。遇到这种情况,系统将自动进行如下处理:

1)先将两个运算数右端对齐。

2)再将位数短的一个运算数往高位扩充,即无符号数和正整数左侧用0补全;负数左侧用1补全;然后对位数相等的这两个运算数,按位进行位运算。

【程序2-5编写一个程序,实现无符号16位数的循环左移n位。

采用unsigned short类型存放无符号16位数。C语言中只有左、右移位,而没有循环移位功能。左移和循环左移的区别在于对从左边(高端)移出的n位数的处理上。左移时,移出的n位数被丢弃,循环左移时,移出的n位数应依次放在右边(低端)的n位上。为将无符号16位数d达到循环左移的目的,实现过程如下:

1)先将d高端的n位数通过“右移”操作移至低端的n位上(高端全为0),把结果存入中间变量a中。

2)再通过“左移”运算将d左移n位(低端移入的全为0),把结果存入另一中间变量b中。

3)最后利用按位或运算将这两个中间变量中的内容“拼装”在一起,完全循环左移功能。

将循环左移功能设计成leftmove()函数,对应的程序如下:

/* 文件名:chap02_5.cpp */

#include <stdio.h>

void leftmove(unsigned short *d,int n)

{

    unsigned short a,b;

    a=*d>>(16-n);

    b=(*d)<<n;

    *d=a|b;

}

void main()

{

    unsigned short d;

    d=0x6271;

    leftmove(&d,4);

    printf("%x\n",d);

}

程序运行结果:

2716