《第11章 位运算.ppt》由会员分享,可在线阅读,更多相关《第11章 位运算.ppt(30页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第第1010章章 位运算位运算11.1 位运算位运算符符11.2 位段位段11.3应用举例应用举例11.1 位运算符当两个运算对象的位数不同时,系统将自动进行如下处理:n先将两个运算数右端对齐。n 再将位数不足的一个运算对象向高位扩充,即:无符号数和正整数左端用0补齐;负数左端用1补齐;然后对位数相等的这两个数按位进行运算。n“按位与”运算(&)n“按位与”运算是将参加运算的两操作对象,按对应的二进制位分别进行“逻辑与”运算。n运算规则为:只有两个相应位都为1时,该位的运算结果才为1;两个相应位的值相异或均为0时,该位的运算结果为0。11.1 位运算符【例11.1】求表达式12&10的值。ma
2、in()char x=12,y=10;printf(“%d,%dn”,x,y);x=x&y;printf(“%d,%dn”,x,y);输出结果为:12,108,1011.1 位运算符n按位与运算用途:n清零:若想将某个存储单元清零,只需将这个存储单元的值与零进行“与”运算。【例11.2】分析下面程序结果main()char ch=46;printf(%d n,ch);ch=ch&0;printf(%d n,ch);输出结果为:46 011.1 位运算符n获取指定位:如果要想获取某数据X的指定位,则可以用一个数与X进行“与”运算,此数在与指定位相同的位上的值为1,其余各位为0。【例11.3】从键
3、盘输入一个整数,判断此数是否能被2整除。#includemain()int x;printf(Please input a number:);scanf(%d,&x);if(x&0 x01)=0)/*通过与运算,只保留该数的最低位,然后判断其是否为0*/printf(n%d can be divided by 2 exactly!,x);/*最低位为0,该数能被2整除*/else printf(n%d cant be divided by 2 exactly!,x);/*最低位为1,不能被2整除*/11.1 位运算符n“按位或”运算(|)n按位或运算是将参加运算的两操作对象,按对应的二进制位分
4、别进行“逻辑或”运算。n运算规则为:只有两个相应位都为0时,该位的运算结果才为0,其它情况下,结果全为1。【例11.4】求表达式12|10的值。main()char x=12,y=10;printf(“%d,%dn”,x,y);x=x|y;printf(“%d,%dn”,x,y);输出结果为:12,1014,1011.1 位运算符n用途:按位“或”经常用来对一个数据的某些位置1。【例11.5】把整数x(8位)的低4位置1,高4位不变。main()char x=67;printf(“%dn”,x);x=x|15;printf(“%dn”,x);输出结果为:677911.1 位运算符n“按位异或”
5、运算()n按位或运算是将参加运算的两操作对象,按对应的二进制位分别进行“按位异或”运算。n运算规则为“按位异或”的应用:参加运算的两个运算量,如果两个相对应位上的值不同,则该位的结果为1;如果对应位上的值相同,则该位的结果为0。n“按位异或”的应用n 使特定位翻转,即使指定的位求反。【例11.6】设x=46,将其高4位保留原样,低4位各位求反。main()char x=46;printf(“%dn”,x);x=x15;printf(“%dn”,x);11.1 位运算符输出结果为:4633n对变量置零。每一个数与它自身进行“异或”运算,结果各位均为零。即:xx=0。【例11.7】不用临时变量,交
6、换两个变量的值。main()char x=12,y=10;printf(“%d,%dn”,x,y);x=xy;y=yx;x=xy;printf(“%d,%dn”,x,y);输出结果为:12,1010,1211.1 位运算符n“按位取反”运算()“按位取反”运算符“”是唯一的一个单目位运算符,用来将一个二进制数按位取反,即将1变0,将0变1。【例11.8】给出一个数的原码,求出该数的补码。main()unsigned int a;/*声明一个无符号的整数a*/unsigned int getbits(unsigned);/*函数声明*/printf(nInput an octal number:
7、);scanf(%o,&a);/*以八进制形式输入一个无符号的整数*/printf(result:%o,getbits(a);/*以八进制形式输出*/11.1 位运算符unsigned int getbits(unsigned value)/*求一个二进制数的补码*/unsigned int z;z=value&10000000;if(z=10000000)z=value+1;/*对负数求其补码*/else z=value;/*正数不变*/return(z);运行情况如下:Input an octal number:2345result:2345再次运行:Input an octal numb
8、er:1252525result:525311.1 位运算符n“左移”运算()n左移运算符“”是双目运算符,左移运算的一般形式为:运算对象运算对象左移位数左移位数n作用:将一个数的各二进制位依次左移若干位(由左移位数给出),左移时,右端(低位)补0,左端(高位)移出的部分舍去。【例11.9】输入两个1位十进制数字符a和b,由a、b组合生成整数c(c用字符类型表示),并显示出来。生成规则是:a的低4位作为c的高4位,b的低4位作为c的低4位。屏蔽掉a,b的高4位;a左移4位,使a的低4位成为高4位;将a和b拼在一起,形成c。11.1 位运算符main()char a,b,c;while(1)/*
9、输入a,b*/printf(Please input a and b:n);scanf(%c%c,&a,&b);if(a=0)&(b=0)break;a=a)n右移运算符“”是双目运算符,右移运算的一般形式为:运算对象运算对象右移位数右移位数n作用:将一个数的各二进制位依次右移若干位(由右移位数给出),右移时,右端(低位)移出的部分舍去,左端(高位)移入的二进制数分两种情况:对于无符号数和正整数,高位补0;对于负整数,高位补1。例如:int a=5,b=-3,x,y;x=a2;y=b2;11.1 位运算符n位复合赋值运算符n注意n位运算的类型可以是整型(int、unsigned或long in
10、t)或字符型(char)数据。n当两个运算对象的类型不同时系统会自动进行如下处理:n两个运算对象按位右对齐;n较短的运算对象高位符号扩展;即如果是正数,高位补0,如果是负数,高位补1。11.2 位段n位段结构类型位段结构是一种构造类型,类型定义的方法为:struct 类型名类型名 基类型基类型 位段名位段名1:位段:位段1占用位数;占用位数;基类型基类型 位段名位段名2:位段:位段2占用位数;占用位数;基类型基类型 位段名位段名n:位段位段n占用位数;占用位数;11.2 位段例如,struct status unsigned a:2;unsigned b:2;unsigned c:3;unsi
11、gned d:3;unsigned e:1;unsigned f:2;unsigned g:3;11.2 位段n位段结构类型变量的定义与引用n位段结构类型的变量位段结构类型的变量的定义方法和其它变量定义方法一样。例如利用上面定义的类型status可以定义变量flag,struct status flag;n位段数据的引用n位段数据的引用方法和结构体成员的引用方式相同。例如,flag.a=2;flag.b=1;n如果所赋值超过了位段所允许的最大范围,系统会自动取数的低位。n关于位段的说明n 位段的基类型必须为unsiged int类型。11.2 位段n可以将类型说明和变量说明一起完成。struc
12、t packed1 unsigned f1:4;unsigned f2:2;unsigned f3:2;data1;n在位段结构中可以定义无名位段。无名位段起位段之间的分隔作用。struct packed2 unsigned f1:4;unsigned f2:2;unsigned :2;/*无名位段,起分隔作用*/unsigned f3:2;data2;11.2 位段n无名位段的长度可以为0,这时,下一个位段从下一个单元存放。struct packed3unsigned f1:4;unsigned f2:4;unsigned :0;/*无名位段长度为0*/unsigned f3:2;data3
13、;11.2 位段n一个位段必须存储在同一存储单元,不能横跨两个存储单元。如果一个单元空间不够,则系统从下一个单元起存放该位段。struct packed4 unsigned f1:8;unsigned f2:4;unsigned f3:6;/*该位段从下一个单元起存放*/unsigned f4:2;data4;11.2 位段n 在位段结构中,不一定必须是位段成员,也可以包含非位段成员。struct packed5 unsigned f1:4;unsigned f2:4;unsigned f3:4;int n;/*非位段成员*/data5;n位段可以在数值表达式中引用,并被系统自动转换成整型数。
14、位段可以在表达式中引用,所以位段也可以以整型格式输出。例如:printf(“%d,%d”,data2.f1,data1.f2);11.3应用举例【例11.10】取一个整数a(用16位存储)从右端开始的47位。解:例如,0000,0000,1101,1001(八进制331,十进制217,47位1101的八进制值是15,十进制13)。方法:先使a右移4位,使要取出的几位移到最右端。a4 设置一个低4位全为1,其余为0 的数(0 4;/*将a右移4位后赋值给变量b*/c=(0 4);/*使低4位全为1,其余为0 */d=b&c;printf(“%on%on”,a,d);11.3应用举例【例11.11
15、】从键盘上输入一个十进制整数,统计该整数所对应的二进制数中1的个数。分析:统计一个整数m中1的个数有两种方法。方法1:循环执行、测试m的第0位是否为1,是则1的个数加1;m右移1位;程序如下:main()int i,count,m;printf(Please input m:);scanf(%d,&m);count=0;11.3应用举例 for(i=0;i1;printf(Numbers of 1 in m=%d,count);方法2:k=1;循环执行、测试m的第k位是否为1,是则1的个数加1;k左移1位。11.3应用举例程序如下:main()int i,count,m,k;printf(Pl
16、ease input m:);scanf(%d,&m);count=0;k=1;for(i=0;i=16;i+)if(m&k)!=0)count+;k=k0111101111110101(注意,不能直接使用运算符,因为,运算符使左面添0或添1。)方法如下:将a的右端n位先放到中间变量b的高n位中。(左移16-n位)b=an;将c与b 进行按位或运算。c=a|b11.3应用举例程序如下:main()unsigned a,b,c;int n;scanf(a=%o,n=%d,&a,&n);/*a以八进制形式输入,右移位数以十进制形式输入*/b=an;c=c|b;printf(%on%o,a,c);/
17、*以八进制形式输出*/11.3应用举例【例11.13】编写函数leftloop,实现将16位数循环左移n位。循环左移可以用下述方法实现:将源操作数送入一中间变量;将中间变量右移16-n位,使高端n位移至低端;将源操作数左移n位;用“按位或”运算将中间变量和源操作数合并在一起。11.3应用举例leftloop(unsigned*value,int n)/*value是源操作数,n是移位位数*/unsigned a,b;a=*value(16-n);b=*valuen;*value=a|b;main()unsigned value,m;printf(Please input value and m:);scanf(%u,%u,&value,&m);/*value是源操作数,m是移位位数*/m=m%16;/*移位位数超过16时*/leftloop(&value,m);printf(value=%un,value);
限制150内