2.4.7 位运算

    无论在什么情况下,数据都是用0和1来存储的,这就是数据的机内表示,有时按位操作数据是很必要的,也就是说,程序员可能希望通过改变内存中某单元的某一位来改变其值,这就是位运算的由来。C++中的位运算符有以下两类。

    ❑位逻辑运算符:&(位“与”)、^(位“异或”)、|(位“或”)和~(位“取反”)。

    ❑移位运算符:<<(左移)和>>(右移)。

    下面分开进行介绍,首先来看<<和>>,可能有的读者会说,这不是前面代码中经常出现的,跟在cin和cout后面的输入输出符吗?没错,但它们在这里起的是移位的作用,而不是用来输入输出的。

    注意

    一个操作符具有多种功能,代表两种及以上不同运算的情形,称为运算符重载。

    1.移位运算符

    移位运算表达式的基本形式为“A<<n;”或“A>>n”,分别代表将数字型量A(整型、浮点型和char型,可以是变量也可以是常量)中存储的0、1序列向左或右移动n位,移动后的值作为整个表达式的输出,但要注意的是,执行移位运算后A的值并没有发生变化,见代码2.11所示。

    代码2.11 移位运算Shift


    <——————————————-文件名:example211.cpp————————————-> 01 #include<iostream> 02 int main() 03 { 04 using namespace std; 05 short A=521,B,C;//声明两个short型变量 06 B=A<<3;//A左移3位,赋值给B 07 C=768>>4;//768右移4位赋值给C 08 cout<<"A is"<<A<<endl;//输出 09 cout<<"B is"<<B<<endl;//输出 10 cout<<"C is"<<C<<endl;//输出 11 return 0; 12 }

    【代码解析】代码第6行是将A(521)左移3位,赋值给B,而第7行是将768右移4位赋值给C。

    输出结果如下所示。


    A is 521 B is 4168 C is 48

    说明

    代码2.11 中,我们对short型变量A和常量768进行了左移位和右移位的操作,之所以采用short而没有采用int来声明变量A,是因为short型变量在内存中占用两个字节,而int型变量不确定,采用short类型抛除了平台相关性的影响。

    代码2.11 中,语句“C=A<<3;”的执行过程如图2.7所示,short型变量A占用两个内存字节,大小为521,其机内形式为00000010 00001001,“A<<3”是将其中的每位都向左移3位,后面的位补以0,并把移位后的结果赋值给变量C。右移运算本质上和左移运算是相通的,这里就不再讲解。

    注意

    移位运算中,左侧的操作符不发生变化,如代码2.11中的A,移位前后都是521。

    2.4.7 位运算 - 图1

    图 2.7 左移位示意图

    移位运算符都是双目的,从左向右结合,优先级与标准的输入输出符相同,关于移位运算有以下两点需要特别强调。

    ❑对空白位补0这一操作是针对无符号数或有符号正数而言,对于有符号的负数,编译器会对符号位进行特殊的处理。

    ❑移位运算符右边的操作数(n)为负数,或者n比左边操作数位数还要长时,会产生不可预期的结果,这取决于该内存区域的存储情况。

    2.4.7 位运算 - 图2

    图 2.8 位取反运算示意图

    2.位取反运算

    位取反运算即对一个数的各位都进行非运算,如图2.8所示。

    位取反运算符是单目的,从右向左结合,其优先级与前面介绍的单目运算符优先级相同,和移位运算一样,位取反运算并不改变操作数的值。

    3.位“与”、位“或”和位“异或”

    位“与”、位“或”和位“异或”是对两个操作数的每一位进行“与”、“或”和“异或”运算如代码2.12所示。

    代码2.12 位“与”与位“或”BitLogic


    <————————————————文件名:example212.cpp———————————> 01 #include<iostream> 02 int main() 03 { 04 using namespace std; 05 short A=521,B=123,C,D;//声明4个short型变量 06 C=A&B;//位与 07 D=A|B;//位或 08 cout<<"C is"<<C<<endl;//输出 09 cout<<"D is"<<D<<endl;//输出 10 return 0; 11 }

    【代码解析】代码第6行是进行位与运算,将A位与B,然后赋值给C。代码第7行是将A位或B,然后赋值给D。

    输出结果如下所示。


    C is 9 D is 635代码2.12中语句“C=A&B;”的执行过程如图2.9所示,A和B中的对应位分别进行“与”运算,图中的4条竖线是从图中16个位的“与”运算选出的最有代表性的,对应了位“与”运算的准则,如下所示。 1&1=1 1&0=0 0&1=0 0&0=0位“或”运算的执行过程与之类似,对应的准则如下所示。 1|1=1 1|0=1 0|1=1 0|0=0通俗地讲,如果位“异或”运算的两个位相同(同为0或同为1),结果为0,若两个位不同(一个为0,另一个为1),结果为1,对应的准则为如下所示。 1^1=0 1^0=1 0^1=1 0^0=0

    位“与”、位“或”和位“异或”运算符都是双目运算符,其结合性都是从左向右的,优先级高于逻辑运算符,低于比较运算符,且从高到低依次为&、^、|。

    注意

    和移位运算符不同的是,位“反”、位“与”、位“或”和位“异或”运算符不关心操作数的符号,只是按操作数所在字节的0、1序列进行比对,符号位会被当成普通的0或1进行处理。

    2.4.7 位运算 - 图3

    图 2.9 位与运算示意图