1、第十三章 位运算,学习目标,位运算的有关概念和运算规律位段的概念,课程内容,13.1 概述13.2 位运算符和位运算13.3位段,13.1 概述,C语言程序设计最大的一个特点就是可以对计算机硬件进行操作,其操作主要是通过位运算实现的。位运算很适合编写系统软件的需要,是C语言的重要特色。在计算机用于检测和控制领域中要用到位运算的知识。所谓位运算就是指进行二进制的运算。在系统软件中,常要处理二进制的问题。例如,将一个存储单元中的各二进制左移或者右移一位,两个数按位相加等。C语言提供位运算的功能,与其他高级语言相比,显然具有很大的优越性。,C语言提供6种位运算符,说明: (1)“为单目运算符,其余均
2、为双目运算符,优先级高低顺序:按位求反 移位 按位与& 按位异或 按位或| (2)运算量只能是整型或字符型数据,浮点数不能参与运算 (3)参与运算时,操作数都必须转换成二进制形式,然后再执行按位运算,13.2 位运算符和位运算,如果左移出的位不是1,则左移操作相当于乘法操作,左移一位相当于原数乘以2,左移n位,则相当于原数乘以2n,左移位运算符 格式:x位数 规则:使操作数的各位左移,低位补0,高位溢出。例:52= 20,右移位运算符 格式:x位数 规则:使操作数的各位右移,移出的低位舍弃,高位补符号位。例:20 2= 5,左移操作相当于除法操作,右移一位相当于原数除以2,右移n位,则相当于原
3、数除以2n,【例13.1】左移位 1 #include 2 void main() 3 4 int a=-1; 5 int i=0; 6 for (i=0; i17; i+) 7 8 printf(“%d%d=%dt“, a, i, ai); 9 printf(“0x%x%d=0x%xn“, a, i, ai); 10 11 ,运行结果如下: -10=-1 0xffff0=0xffff -11=-2 0xffff1=0xfffe -12=-4 0xffff2=0xfffc -13=-8 0xffff3=0xfff8 -14=-16 0xffff4=0xfff0 -15=-32 0xffff5=
4、0xffe0 -16=-64 0xffff6=0xffc0 -17=-128 0xffff7=0xff80 -18=-256 0xffff8=0xff00 -19=-512 0xffff9=0xfe00 -110=-1024 0xffff10=0xfc00 -111=-2048 0xffff11=0xf800 -112=-4096 0xffff12=0xf000 -113=-8192 0xffff13=0xe000 -114=-16384 0xffff14=0xc000 -115=-32768 0xffff15=0x8000 -116=0 0xffff16=0x0,整型数据是采用补码表示的。每
5、左移一位相当于数据乘以2,当移位结果超出数据表示范围时,结果就不再正确。,【例13.2】右移位1 #include 2 void main() 3 4 int a=0xc57f; 5 int i; 6 for (i=0; i%d=%dt“, a, i, ai); 9 printf(“0x%x%d=0x%xn“, a, i, ai); 10 11 ,运行结果如下: -149770=-14977 0xc57f0=0xc57f -149771=-7489 0xc57f1=0xe2bf -149772=-3745 0xc57f2=0xf15f -149773=-1873 0xc57f3=0xf8af
6、-149774=-937 0xc57f4=0xfc57 -149775=-469 0xc57f5=0xfe2b -149776=-235 0xc57f6=0xff15 -149777=-118 0xc57f7=0xff8a -149778=-59 0xc57f8=0xffc5 -149779=-30 0xc57f9=0xffe2 -1497710=-15 0xc57f10=0xfff1 -1497711=-8 0xc57f11=0xfff8 -1497712=-4 0xc57f12=0xfffc -1497713=-2 0xc57f13=0xfffe -1497714=-1 0xc57f14=
7、0xffff -1497715=-1 0xc57f15=0xffff,整数-14977的补码是0xc57f。整型数据每右移一位相当于数据除以2,同时还注意到-1/2=-1。,其他位运算 除了移位运算,二进制数据的位运算还包括与、或、非、异或四种类型。 从数据本身的角度来看,位运算本身的意义不大。但是在跟计算机硬件相关的很多操作中,位运算有其他运算无可比拟的优势。,位运算真值表,【例13.3】将数据的最末位置位为0。 1 #include 2 void main() 3 4 int aValue; 5 int i; 6 for (i=0; i5; i+) 7 8 printf(“Please i
8、nput a integer:“); 9 scanf(“%d“, 12 13 ,运行结果如下:Please input a integer:19 The new value is:18 Please input a integer:1221 The new value is:1220 Please input a integer:12 The new value is:12 Please input a integer:17 The new value is:16 Please input a integer:400 The new value is:400,【例13.4】字符串的简单加密 1
9、 #include 2 #include 3 void main() 4 5 char maskChar=0x55; 6 char *sourceString=“Hello“; 7 char *destString1; 8 char *destString2; 9 int i; 10 destString1=malloc(strlen(sourceString); 11 destString2=malloc(strlen(sourceString); 12 for (i=0; istrlen(sourceString); i+) 13 destString1i=sourceStringimas
10、kChar; 14 destString1i=0; 15 for (i=0; istrlen(sourceString); i+) 16 destString2i=destString1imaskChar; 17 destString2i=0; 18 printf(“sourceString=%sn“, sourceString); 19 printf(“destString1=%sn“, destString1); 20 printf(“destString2=%sn“, destString2); 21 ,运行结果如下: sourceString=Hello destString1=099
11、: destString2=Hello,【例13.5】AD574是一种A/D转换器,它的作用就是将模拟信号转换成数字信号。它对外有2个端口,分别叫作偶地址端口和奇地址端口。向偶地址端口发送命令可以启动A/D转换,从偶地址端口读取数据可以获取A/D转换是否完成的状态。在A/D完成后,从偶地址可以获取转换数据的高8位数据,从奇地址可以获取低4位数据。假设根据硬件连接情况,得到端口地址0x500和0x501。在C语言的库函数中,有访问外设端口的outportb函数,它将一个字节数据写入外设端口寄存器。inportb函数把端口寄存器中一个字节读入CPU。下面的程序给出了一个数据采集函数。 1 unsi
12、gned ad_convert () 2 3 unsigned ad_h8 = 0 ; 4 unsigned ad_L4 = 0 ; 5 unsigned ad_result = 0; 6 outportb(0x500 ,0xff); 7 while (inportb(0x500) 14 ,13.3 位段,我们知道计算机中信息的存储一般是以字节为单位的。实际上,有时一个信息本身可能用不到那么多位。例如,要表示人的性别只需1位二进制数据就可以,譬如0代表“男”,1代表“女”。再例如在过程控制领域,一个字节的数据可以表示多个命令或者设备的多个状态特征。 虽然可以用移位或其他位运算组合成我们需要的信
13、息,但是,C语言提供了更方便的利用位段结构处理信息的方法。,位段:在一个结构体中可以以位为单位来指定 其成员所占内存长度,这种以位为单位 的成员称为位段(或位域)。,如:struct packed_data unsigned a : 2;unsigned b : 3;unsigned c : 4;int i;data;,位段的引用:,结构体变量名. 位段成员名,如:struct packed_data unsigned a : 2;unsigned b : 3;unsigned c : 4;int i;data;,位段的引用如下:data.a=2;data.b=7;data.c=9;,【例13
14、.6】定义位段 1 typedef struct 2 3 unsigned a:3; 4 unsigned b:1; 5 unsigned c:7; 6 Some_bits; 7 #include 8 void main() 9 10 Some_bits theseBits; 11 unsigned int *pInteger; 12 pInteger=(unsigned int *) 20 ,位段的定义,位段的赋值,位段的引用,运行结果如下: sizeof(Some_bits)=2 *pInteger=10e 6,1,16,有定义的位段位于整个结构数据的低位。,在位段中定义无名字段含义:跳过
15、该字节剩余的位或指定的位不用。当无名字长度为0时,跳过该字节剩余的位不用;当无名字段长度为n时,跳过n位不用。,如:struct packed_data unsigned a : 2;unsigned b : 3;unsigned : 0;unsigned c : 4;int i;data;,【例13.7】未命名位段举例。 1 typedef struct 2 3 unsigned a:3; 4 unsigned :2; 5 unsigned b:1; 6 unsigned :0; 7 unsigned c:7; 8 Unamed_bits; 9 #include 10 void main() 11 12 Unamed_bits theseBits; 13 unsigned int *pInteger; 14 pInteger=(unsigned int *) 22 ,运行结果如下: sizeof(Unamed_bits)=2 *pInteger=1026 6,1,16,位段结构,