




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第8章位运算
在计算机中,数据是由二进制表示的,一个字符占用若干二进制位。在一些系统软件中,常要对某些数据的二进制位进行处理,例如,对某些二进制位清零、将一个存储单元中的各二进制位左移或右移等。
C语言中对二进制位的运算称作位运算。位运算的对象只能是整型数据和字符型数据。
8.1位运算与位运算符C语言中提供了六种位运算符。表8.1位运算符的运算功能和优先级运算符含义优先级~按位求反高低<<>>左移右移&^|按位与按位异或按位或①先将两个运算数右端对齐。②再将位数不足的一个运算对象向高位扩充,即:无符号数和正整数左端用0补齐;负数左端用1补齐;③然后对位数相等的这两个数按位进行运算。注意:只有按位求反运算符(~)为单目运算符,其余均为双目运算符。当两个运算对象的位数不同时,系统将自动进行如下处理:8.1.1“按位与”运算(&)
“按位与”运算是将参加运算的两操作对象,按对应的二进制位分别进行“逻辑与”运算,运算规则为:只有两个相应位都为1时,该位的运算结果才为1;两个相应位的值相异或均为0时,该位的运算结果为0。如下所示:
1&1=10&1=01&0=00&0=0;
【例8.1】求表达式12&10的值。main(){charx=12,y=10;printf(“%d,%d\n”,x,y);x=x&y;printf(“%d,%d\n”,x,y);}输出结果为:运算过程如下:
12:00001100&10:00001010结果:00001000
按位与运算主要包括以下用途:①清零如果想将某个存储单元清零,只需将这个存储单元的值与零进行“与”运算,即可达到清零的目的。【例8.2】分析下面程序结果main(){charch;ch=46;printf("%d\n",ch);ch=ch&0;printf("%d\n",ch);}输出结果为:其运算过程如下:
46:00101110
&0:00000000
结果:00000000②获取指定位
要想获取X的指定位,则用一个数与X进行“与”运算,此数在与指定位相同的位上的值为1,其余各位为0。
例如:取X的2、3、4、5位上的值,表达式为:Y=X&60。
X:xxxxxxxx
&60:00111100
结果:00xxxx00
#include<stdio.h>main(){intx;printf("Pleaseinputanumber:");scanf("%d",&x);if((x&0x01)==0)/*通过与运算,然后判断结果最低位其是否为0*/printf("\n%dcanbedividedby2exactly!",x);/*最低位为0, 该数能被2整除*/elseprintf(“\n%dcan’tbedividedby2exactly!”,x);/*最低位 为1,该数不能被2整除*/}输入24,输出结果为:【例8.3】从键盘输入一个整数,判断此数是否能被2整除。
解:一个整数能否被2整除,只需判断最低位是0还是1。若最低位为0,则能被2整除;若为1,则不能被2整除。8.1.2“按位或”运算(|)
按位或运算是将参加运算的两操作对象,按对应的二进制位分别进行“逻辑或”运算,运算规则为:只有两个相应位都为0时,该位的运算结果才为0,其它情况下,结果全为1。如下所示:
0|0=0
1|1=1
0|1=1
1|0=1
按位“或”经常用来对一个数据的某些位置1。【例8.4】求表达式12|10的值。
main()
{charx=12,y=10;
printf(“%d,%d\n”,x,y);
x=x|y;
printf(“%d,%d\n”,x,y);
}
输出结果为:
运算过程12|10=14
12:00001100
|10:00001010
结果:00001110
【例8.5】把整数x(8位)的低4位置1,高4位不变。main(){charx=67;printf(“%d\n”,x);x=x|15;printf(“%d\n”,x);}输出结果为:
计算过程如下:
X:01000011
|15:00001111
结果:010011118.1.3“按位异或”运算(^)
按位异或运算是将参加运算的两操作对象,按对应的二进制位分别进行“按位异或”运算,运算规则为:参加运算的两个运算量,如果两个相对应位上的值不同,则该位的结果为1;如果对应位上的值相同,则该位的结果为0。如下所示:
1^1=0
0^0=0
1^0=1
0^1=1
例如:求表达式210^127的值。
运算过程如下:
210:11010010
^127:00111111
结果:11101101
即:210^127=237
“按位异或”的应用主要包括:
①使特定位翻转,即使指定的位求反。【例8.6】设x=46,将其高4位保留原样,低4位各位求反。分析只须将x与00001111进行异或运算即可。main(){charx=46;printf(“%d\n”,x);x=x^15;printf(“%d\n”,x);}输出结果为:
运算过程
00101110^00001111
结果:00100001
“按位异或”的应用主要包括:
①使特定位翻转,即使指定的位求反。【例8.6】设x=46,将其高4位保留原样,低4位各位求反。分析只须将x与00001111进行异或运算即可。main(){charx=46;printf(“%d\n”,x);x=x^15;printf(“%d\n”,x);}②对变量置零。每一个数与它自身进行“异或”运算,结果各位均为零。即:x^x=0。
【例8.7】不用临时变量,交换两个变量的值。
main()
{charx=12,y=10;
printf(“%d,%d\n”,x,y);
x=x^y;y=y^x;x=x^y;
printf(“%d,%d\n”,x,y);
}
输出结果为:
运算过程
x:00001100
^y:00001010x:00000110
^y:00001010y:00001100
^x:00000110x:00001010注意:三条语句的先后顺序不能变。8.1.4“按位取反”运算(~)
“按位取反”运算符“~”是唯一的一个单目位运算符,用来将一个二进制数按位取反,即将1变0,将0变1。
运算规则如下:
~1=0
~0=1 【例8.8】给出一个数的原码,求出该数的补码。
解:一个正数的补码等于该数的原码,一个负数的补码等于该数的反码加1。
main()
{unsignedinta;/*声明一个无符号的整数a*/
unsignedintgetbits(unsigned);/*函数声明*/
printf(“\nInputanoctalnumber:”);
scanf(“%o”,&a);/*以八进制形式输入一个无符号的整数*/
printf(“result:%o”,getbits(a));/*以八进制形式输出*/
}
unsignedintgetbits(unsignedvalue)/*求一个二进 制数的补码*/
{unsignedintz;
z=value&10000000;
if(z==10000000)z=~value+1;/*对负数求其补码*/
elsez=value;/*正数不变*/
return(z);
}
先后输入2345和1252525的运行情况如下:
8.1.5“左移”运算(<<)左移运算的一般形式为:运算对象<<左移位数左移运算符“<<”是双目运算符,它的作用是:将一个数的各二进制位依次左移若干位(由左移位数给出),左移时,右端(低位)补0,左端(高位)移出的部分舍去。
设a=6,则a<<2的值为24:
a:00000110(a=6)
a<<2:00011000(b=24=4*6)左移时,若左端移出的部分不包含有效二进制数1,则每左移一位,相当于移位对象乘以2。在某些情况下,可以利用左移的这一特征来代替乘法运算,以加快运算速度。【例8.9】输入两个1位十进制数字a和b,由a、b组合生成整数c(c用字符类型表示),并显示出来。生成规则是:a的低4位作为c的高4位,b的低4位作为c的低4位。
解:要想用a、b的低4位组成c,需要做以下工作:
①屏蔽掉a、b高4位;
②a左移4位,使a的低4位成为高4位;
③将a和b拼在一起,形成c。main()
{chara,b,c;
while(1) /*输入a,b*/
{printf("Pleaseinputaandb:\n");
scanf("%c,%c",&a,&b);
if((a<='9')&&(a>='0')&&(b<='9')&&(b>='0'))break;
}
a=a<<4; /*a左移4位,低4位移至高4位*/
b=b&0x0f; /*屏蔽b的高4位*/
c=a|b;
printf("c=%d\n",c);
}
/*例8.9程序*/8.1.6“右移”运算(>>)
右移运算的一般形式为:运算对象>>右移位数
右移运算符“>>”是双目运算符,它的作用是:将一个数的各二进制位依次右移若干位(由右移位数给出),右移时,右端(低位)移出的部分舍去,左端(高位)移入的二进制数分两种情况:无符号数和正整数,高位补0;负整数,高位补1。
例如:
inta=5,b=-3,x,y;
x=a>>2;
y=b>>2;
用二进制数表示的运算过程如下:
a的二进制补码表示:00000101
x=a>>2:00000001
b的二进制补码表示:11111101
y=b>>2:111111118.1.7位复合赋值运算符
类似于算术运算的复合赋值运算符,位运算符和赋值运算符也可以构成位复合赋值运算符。
表10.2由位运算符构成的复合运算符
复合运算符名称表达式等价的表达式&=按位与赋值a&=ba=a&b|=按位或赋值a|=ba=a|b^=按位异或赋值a^=ba=a^b>>=右移位赋值a>>=ba=a>>b<<=左移位赋值a<<=ba=a<<b注意:位运算的类型可以是整型(int、unsigned或longint)或字符型(char)数据。当两个运算对象的类型不同时系统会自动进行如下处理:⑴两个运算对象按位右对齐;⑵较短的运算对象高位符号扩展;即如果是正数,高位补0,如果是负数,高位补1。
8.2位段及使用
计算机中一般以字节为单位存放数据,但实际工作中有时数据的表示不必用一个字节,仅仅占用一个字节的一位或几位即可。例如,某系统有7种设备a,b,c,d,e,f,g,设备a有4种状态,设备b有3种状态,设备c有8种状态,设备d有8种状态,设备e有1种状态,设备f有4种状态,设备g有6种状态。如果每一种设备的状态用一个字节表示,共需要7个字节。实际上设备a有4种状态,用2位表示即可,即使对于有8种状态的设备c和d,用3位二进制表示也就够了。7种设备总共用16位二进制数,用一个无符号整型变量flag来表示即可。
利用位运算可以处理这些标志信息比较麻烦。
例如对于上述系统b设备3种状态用flag的第12、13位表示,如果b的状态为01,
●利用位运算来设置变量flag的方法可以为:
将01存入一个临时变量temp;
将temp左移12位,将01移至到第12、13位;
将flag和temp进行“按位或”运算。
●使用flag中设备b的状态信息,可能需要进行以下操作:
将flag内容送至临时变量temp;
将temp与0x3000进行“按位与”运算,屏蔽掉除12、 13位的其它位;
temp右移12位。
8.2.1位段结构类型
C语言提供了位段操作,可以方便地实现对一个变量的某些位进行处理。所谓位段,是以位为单位定义长度的一种结构类型的成员。
位段结构是一种构造类型,类型定义的方法为:
struct类型名
{基类型位段名1:位段1占用位数;
基类型位段名2:位段2占用位数;
…;
基类型位段名n:位段n占用位数;
};
例:上面所述系统的位段结构类型可以定义为:
structstatus
{unsigneda:2;
unsignedb:2;
unsignedc:3;
unsignedd:3;
unsignede:1;
unsignedf:2;
unsignedg:3;
};
位段结构类型名为status,它包含7个位段(bitfield),每个位段的数据类型都是unsigned,每个位段所占的二进制位数由冒号后面的数字指定。8.2.2位段结构类型变量的定义与引用
1.位段结构类型的变量
定义了位段结构类型后,就可以定义相应的位段结构类型的变量了。位段结构类型的变量的定义方法和其它变量定义方法一样。
例如利用上面定义的类型status可以定义变量flag。
structstatusflag;
位段的存放位置由编译系统分配,不同的编译系统分配方式不同,有的系统从左到右分配,有的系统则从右到左。程序设计人员不必考虑具体的分配方式,可以直接利用位段名对位段进行操作。2.位段数据的引用
●位段数据的引用方法和结构体成员的引用方式相同,例如可以为flag的成员a赋值:
flag.a=2;\*a的值为10*\
flag.b=1;\*b的值为01*\
●如果所赋值超过了位段所允许的最大范围,系统会自动取数的低位。例如:
flag.a=5;
由于5的二进制形式为101,位段a只有2位,所以结果a的值为01。3.关于位段的说明
位段的定义和引用,需要注意以下几点:
①位段的基类型必须为unsigedint类型。
②可以将类型说明和变量说明一起完成。例如:
structpacked1
{unsignedf1:4;
unsignedf2:2;
unsignedf3:2;
}data1;③在位段结构中可以定义无名位段。无名位段起位段之间的分隔作用。例如:
structpacked2
{unsignedf1:4;
unsignedf2:2;
unsigned:2; /*无名位段,起分隔作用*/
unsignedf3:2;
}data2;
该位段结构中的第3个位段为无名位段,它占用2位二进制位,它的作用是将f2和f3两个位段分割开。1512111098760f1f2空f3图8.1④无名位段的长度可以为0,使下一个位段从下一个单元存放。例如:
structpacked3
{unsignedf1:4;
unsignedf2:4;
unsigned:0; /*无名位段长度为0*/
unsignedf3:2;
}data3;
如果没有长度为0的无名位段,位段f3应该和位段f2相邻存放,由于长度为0的无名位段的存在,位段f3被分配到下一个单元。
151211109876015140f1f2f3⑤一个位段必须存储在同一存储单元,不能横跨两个存储单元。如果一个单元空间不够,则系统从下一个单元起存放该位段。
structpacked4
{unsignedf1:8;
unsignedf2:4;
unsignedf3:6;/*该位段从下一个单元起存放*/
unsignedf4:2;
}data4;
由于f1和f2占用了12位,f3需要6位,第一个单元剩余的4位放不下,于是f3从第二个单元开始存放。
f1158743015109870f4f3f2
因为一个位段不能横跨两个单元,所以一个位段的长度不能超过一个字长。
位段不能说明为数组,也不能用指针指向位段。⑥在位段结构中,不一定必须是位段成员,也可以包含非位段成员。例如:
structpacked5
{unsignedf1:4;
unsignedf2:4;
unsignedf3:4;
intn; /*非位段成员*/
}data5;
其中intn定义了一个整型变量,而不是一个位段。
150150nf2f1f3⑦位段可以在数值表达式中引用,并被系统自动转换成整型数。例如:
data5.f1+5;
data4.f2+15/data5.f1;
都是合法的表达式。请读者自己分析这两个表达式的值。
位段既然可以在表达式中引用,位段也就可以以整型格式输出。
例如:
printf(“%d,%d”,data2.f1,data1.f2);
当然也可以用%u,%o,%x等格式输出。8.2.3应用举例
【例8.10】取一个整数a(用16位存储)从右端开始的4~7位。
解:例如,0000,0000,1101,1001(八进制331,十 进制217;4~7位1101的八进制值是15,十进 制13)。
方法:
①先使a右移4位,使要取出的几位移到最右端。a>>4
②设置一个低4位全为1,其余为0的数~(~0<<4)
③将上面两者进行&运算。
main()
{unsigneda,b,c,d;
scanf(“%o”,&a);/*以八进制形式输入一个无符号的整数*/
b=a>>4;/*将a右移4位后赋值给变量b*/
c=~(~0<<4);/*使低4位全为1,其余为0*/
d=b&c;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 正面管教课题申报书
- 内蒙古教学课题申报书
- 自筹课题申报书范文格式
- 十三五课题申报书历史
- 数字法学课题申报指南书
- 课题申报书代写
- 业务交易合同范本
- oem合同范本简版
- 教育教研课题申报书
- 供货企业供货合同范本
- 人教版(PEP)五年级英语下册第一单元测试卷-Unit 1 My day 含答案
- 企业名称预先核准通知书
- 统筹管理方案
- 建筑工程安全文明施工标准化图集(附图丰富)
- 人教版 美术二年级上册 第9课 蜻蜓飞飞 教案
- Unit 1 Travel教案-2023-2024学年高一下学期 中职英语高教版(2023修订版)基础模块2
- DB3206T 1083-2024机关会议服务人员操作技术规范
- 1.3.1-二项式定理-公开课一等奖课件
- 垃圾清运突发事件应急预案
- 中医淋巴排毒
- 提高钻孔灌注桩成孔质量一次验收合格率
评论
0/150
提交评论