c语言设计(第二版)---------------教学课件制作人:黄荧制作人单位:河师大数学与信息科学学院第十二章位运算(按位运算)几种关于二进制的按位运算:1按位与、按位或2异或、取反3左移、右移4位段00000011&)000001010000000100110000|)0000111100111111按位运算的用途:1按位运算主要在编写系统软件和应用软件中使用2按位运算能实现在一个字节中存储多个标志性数据如,一个取值为0,1的标志变量只需要1个数位;存放黑白两色也只需要1个数位.即使存放8种颜色也仅只需要3个数位.3利用按位运算可以非常方便的从一个字节中读取和写入一个或几个数位上的数据.§12.1位运算符和位运算(位:指的是二进制的位!!!)C语言提供的六种位运算:说明:1)除了~取反运算以外,都是二元运算。2)运算量只能是整型或字符型数据,不能是实型数据。运算符含义运算符含义&按位与~取反|按位或左移^按位异或右移§12.1.1按位与运算符(&)(特别注意:&与&&的区别)运算规则:0&0=0,0&1=0,1&0=0,1&1=1如:3&5=?(3)补=00000011&(5)补=0000010100000001∴3&5=1练习2-10&7=?(-10)补=11110110&(7)补=0000011100000110即,-10&7=6练习110&7=?(10)补=00001010&(7)补=0000011100000010即,10&7=2练习310&-10=?(10)补=00001010&(-10)补=1111011000000010即,10&-10=2按位与运算的3个常用的特殊用途:1)清零处理:a=a&02)取一个数的某些位:设a为占2个字节的无符号数,(a)若取a的高8位c=a&(1111111100000000)2=a&(01777400)8(b)取a的低8位:c=a&(0000000011111111)2=a&(0377)83)保留一个数的某些位(其他位置0):如,若保留a的从右数第3,4,5,7,8位a=a&(0000000011011100)2=a&(0334)8§12.1.2按位或运算符(|)(注意:|与||的区别)运算规则:0|0=0,0|1=1,1|0=1,1|1=1如:求060|017=?00110000|)0000111100111111即,060|017=077按位或的一个常用的特殊用途:将某些数位上的值置为1:如:1)将a的低4位置1,高4位不变作:a=a|(00001111)2=a|(017)82)将a的高4位置1,低4位不变:作:a=a|(11110000)2=a|(0360)8§12.1.3异或运算符(^)运算规则:00=0,01=1,10=1,11=0即,相同取0,相异取1如:071052=?00111001^)0010101000010011071052=023异或运算的3个特殊应用:①与1作异或,使特定位翻转:如:将a的低四位翻转:a=a(00001111)2=a017②与0作异或,保留原值a0=a③交换a,b的值,不用临时变量要交换a,b的值,用下列3个赋值语句即可:a=ab;b=ba;a=ab∵b=b(ab)=abb=a0=a类似地:a=(ab)(b(ab))=aabbb=00b=b§12.1.4“取反”运算符(~)(一元运算)运算规则:~0=1,~1=0如:求~025,其中025为整型数占2个字节。~025=~(0000000000010101)2=(1111111111101010)2=0177752特别注意:取反的值是与其所占字节数相关的!!!取反运算的一个特殊应用:将一个数的最低位置零。当整数为16位:a&(1111111111111110)2=a&0177776而当整数为32位:a&(1111…1110)2=a&037777777776︾二者可以统一如下表示:a=a&~115个1因为当系统为16位时,~1=11……1031个1因为当系统为32位时,~1=11……10§12.1.5左移运算符()an功能:将a的二进制数位依次左移n位,右边补零如:a=15,a=a1;15=(00001111)2151=(00011110)2=036=30类似的:a=15,a=a2;152=(00111100)2=074=60但是:a=128,a=a1;128=(10000000)21281=(00000000)2=0(出现溢出!!!)很容易看出,当无溢出时:a1a*2ana*2n§12.1.6右移运算符()an作用:将a的各二进制数位依次右移n位,左边补0或补1。无符号数:左补0有符号数:a=0:左补0a0:逻辑右移:左补0算术右移:左补1TurboC采用的是算术右移。如,1)a=017a2=(00001111)22=(00000011)2=032)a=-7a2=(11111001)22=(11111110)2(补)=-2另外:与左移类似a1a/2(整除)ana/2n(整除)但注意到负数的舍入方向与正数不同,-7/2=-4向远离0的方向舍入。§12.1.7位运算赋值运算符∵&,|,^,等,都为二元运算;∴也可以形成扩展的赋值运算。如:a=a&ba&=ba=a|ba|=ba=a^ba^=ba=aba=ba=aba=b§12.1.8不同长度的数据进行按位运算不同长度的数据进行按位运算,效果可能不同:如:longa=2;intb=2;a=~a;b=~b;所得到的结果是不同的。§12.2位运算举例例12.1取一个整数a从右端开始的4~7位。(注意到,内存中的最低位是0位。)方法1:(最简单的方法)①右移4位,将所取位移至最低位:b=a4;②取出最低4位:c=b&(0000000000001111)2即,c=b&017;方法2:将方法1②的017用反运算表示。构造017的要点是:用反运算构造一个高位为0,低4位为1的数。a)从0开始,0=0…0000(可16位,也可32位)b)取反:~0=1…1111(可16位,也可32位)c)左移4位使低4位为0(可一般化为n):~04d)再取反即得所要求的数:~(~04)即:方法2:①b=a4;②c=~(~04);③d=b&c;所要取的4位1512840例12.1取一个整数a从右端开始的4~7位。(程序)#includestdio.hvoidmain(){unsigneda,b,c,d;scanf(%o,&a);b=a4;c=~(~04);d=b&c;printf(%o\n%o\n,a,d);}方法2:①b=a4;②c=~(~04);③d=b&c;考虑:一般地,从右面的第m位开始取其右边的n位?作:1)b=a(m-n+1);(将第m位开始的n位移至最低位)2)c=~(~0n);(构造低n位为1,高位为0的数)3)a=b&c;(利用按位与运算取出这n位)n0mm-n+1例12.2右循环位移。即:将a各数位依次右移且将最低位上的溢出位放入最高位。如:右循环位移1位.右循环位移n位.处理方法:①取出a中低n位放在b中高n位保存:b=a(16-n)②将a中的高16-n位移至最低位:c=an(a为无符号数)③将b与c作按位或即得所求:c=c|bn位an位b例12.2右循环位移。(程序)#includestdio.hvoidmain(){unsigneda,b,c;intn;printf(Enterunsigneda,intn:\n);scanf(%o%d,&a,&n);b=a(16-n);c=an;c=c|b;printf(%o%o\n,a,c);}右循环位移方法:①取出a中低n位放在b中高n位保存:b=a(16-n)②将a中的高16-n位移至最低位:c=an③将b与c作按位或即得所求:c=c|b§12.3位段(位域)位段是为了使一个字节中的数位的读取更为方便直观而设置的.位段是结构体中特殊的成员,它们是以数位来定义长度的,而不是以字节。如,structpacked_data{unsigneda:2;/*成员a为一个占2个二进制数位的位段。*/unsignedb:6;/*b,c,d也为位段*/unsignedc:4;unsignedd:4;inti;}data;abcdidata如图所示(一小格代表2个数位):(共4个字节)位段的引用对段位可以象一般整型变量要样给它赋值,但需要注意的是:不要超出它的取值范围。如:structpacked_data{unsigneda:2;unsignedb:3;unsignedc:4;inti;}data;data·a=3;√data·a=6;×因为a仅占2个二进制数位,最大存储的数值为3。(溢出错误)例各位段长度之和可以不为整字节。如,structpacked_data{unsigneda:2;unsignedb:3;unsignedc:4;inti;}data;(共4个字节)abc空闲(7)idata如图所示(一小格代表2个数位):三个位段共9个数位。位段的定义和引用的几点说明:(1-7)1)位段成员的类型必须指定为unsigned或int类型。2)若某一位段要从另一个字开始,可以利用长度为0的位段来实现(规定)。c空闲a12bit4bit14bit如:unsigneda:1;unsignedb:2;unsigned:0;unsignedc:3;3)一个位段必须存储在同一个存储单元(一个字,不是字节)中,不能跨两个存储单元。如:unsigneda:12;unsignedb:14;4)可以定义无名位段。5)位段的长度不能大于一个字,也不能定义位段数组。6)可以用整型格式符输出如,用%d,%o,%x,%u等格式输出7)可以用于表达式中,它会被系统自动转化为整型的。a:1空闲(2)c:3如:unsigneda:1;unsigned:2;/*这两位不用*/unsignedb:3;Ch12位运算§1按位与:&§2按位或:|§3按位异或:^§4按位取反:~§5左移:§6右移:§7位段00111001^)0010101000010011~)000101011110101000000011&)0000010100000001