零基础入门语言篇十一章位运算_第1页
零基础入门语言篇十一章位运算_第2页
零基础入门语言篇十一章位运算_第3页
零基础入门语言篇十一章位运算_第4页
零基础入门语言篇十一章位运算_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十一位运算C语言既具有高级语言的特点,也具有低级语言的特点。本节所讲的位运算就具有低级语言的特点,并被广泛用于对底层硬件、外围设备的状态检测和控制。计算机真正执行的是由0和1信号组成的计算机指令,数据也是以二进制形式表示的。因此最终要实现计算机的操作,就要对这些0和1进行操作。每一个0和1的状态称为一个“位”(bit)的状态。有了位运算,C语言就能编写出直接对计算机硬件进行操作的程序。本章主要内容11.1位运算及位运算符概述11.2位运算11.3位域11.4位运算应用举例11.1位运算及位运算符概述11.1.1位运算概述所谓位运算是指对操作数以二进制位(bit)为单位进行的数据处理。每一个二进制位只能存放1位二进制数“0”或“1”,因此位运算符的运算对象是一个二进制数位的集合。通常把组成一个数据的最右边的二进制位称作第0位,从右向左依次称为第1位,第2位,…,最左边一位称作最高位。11.1.2位运算符位的种类C语言中,位运算包括逻辑位运算和移位位运算。1、逻辑位运算分为四种:位反、位与、位或、位异2、移位位运算分为二种:左移与右移。在c语言中的移位不是循环移动,经过移位后一端的位被“挤掉”,而另一端空出的位补0。3、位复合赋值运算符类似于算术的复合运算符,位运算符和赋值运算符也可以构成复合赋值运算符。4、关于位运算符的几点说明(1)在逻辑位运算中,~的优先级高于算术运算符、关系运算符、逻辑运算符,其他位运算符则低于关系运算符、高于逻辑运算符。(2)参加位运算的操作数必须是整型或字符型数据(常量或变量),不能是其它类型的数据。(3)两个长度不同的数据进行位运算时,系统先将两者的右端对齐,短的运算对象若是有符号数则按符号位扩展,若是无符号数则以“0”扩充。(4)位运算符的优先级如下:按位取反运算符“~”的优先级最高,高于所有的双目运算符;其次是左移运算符“<<“和右移运算符“>>”,其优先级高于关系运算符;最低的是按位与“&”、按位异或“∧”和按位或“|”运算符,其优先级低于关系运算符。(5)除了按位取反运算符“~”的结合方向是自右至左外,其余位运算符的结合方向都是自左至右(6)位运算符和逻辑运算符很相似,要注意区别。关系运算和逻辑运算的结果只能是1或0,而按位运算的结果不一定是1或0,还可以是其它数。11.2位运算任务提出:如何统计一个字符对应的ASCII码中1的个数?任务分析:此问题首先要从键盘输入一个字符,然后统计出该字符对应的ASCLL码值转换成二进制后1的个数。 解决此问题的难点在于如何判断该字符对应ASCII码值转换成二进制后每个位上的数字是0还是1。设从键盘输入的字符用ch表示,该问题需对字符ch的ASCII码的每一位进行测试,判断是0还是1。方法是:设置一个屏蔽字与ch进行“&”运算,从而取所需的某位的状态(0或1)。从高位开始,第8位所需设置的屏蔽字mask为0x80,即二进制10000000,若ch&mask的结果为0,则说明ch的第8位为0,否则为1。第7位所需设置的屏蔽字mask为0x40,即将mask右移一位。如此一直下去,直到结束。#include"stdio.h"main(){charch;intmask,i,count=0;printf("请输入一个字符:");ch=getchar();printf("该字符的ASCII是%d\n",ch);mask=0x80;for(i=0;i<8;i++){if((ch&mask)!=0)count++;mask>>=1;}printf("ASCII中1的个数有:%d\n",count);getch();}11.21按位取反运算按位取反运算是用来对二进制按位进行取反运算,是单目运算符。按位取反运算符用“~”表示。按位取反运算符是位运算中惟一的单目运算符,运算对象应置于运算符的右边。1、按位取反运算的运算规则按位取反运算的运算规则:把运算对象的内容按位取反,将每一位上的0变1,1变0。即~0=1,~1=0。例如:对十六进制数32进行取反。~00110010=11001101结果为11001101。又如:a=0000000000001011,则表达式~a的值为1111111111110100。unsignedchara,b; /*定义两个无符号字符型变量a,b*…b=~a /*对变量a全部位取反,结果赋值给b*/…printf("~a=%d\n",b); /*输出十进制b值*/2、按位取反运算的主要应用按位取反运算的主要应用:用来适应不同字长型号的机型,帮助得到使原数最低位为0。例如:想使a中最低位为0,可让a=a&~1。如果a是16位,其中~1等于0177776,与a相与后,使最低位为0。如果是a是32位,其中~1等于0377776,与a相与后,使最低位为0。总之,不管什么样的机型,只要用a=a&~1,就可以使原数的最低位为0,而其余位不变。11.2.2按位与运算按位与运算是指参与运算的两个数对应的二进制位进行逻辑与的操作,用“&”表示。1、按位与运算符的规则按位与运算符的规则:若两个运算对象的对应二进制数位均为1,则结果的对应数位为1,否则为0。按位与运算可能的运算组合及其运算结果如下所示:0&0=01&0=00&1=01&1=1即当两个数对应的位全为1时,得到的该位就为1,只要对应的位有一个0,得到的该位就为0。按位与运算的特点:二进制数的任何数位,只要和数位0进行“与”运算,该位清零;和数位1进行“与”运算,该位保留原值不变。例如,x=0000000000001011,y=0000000000001010,则表达式x&y的计算结果如下:2.按位与运算的主要应用(1)按位清零:只要把需要进行清零的位与0进行“按位与”操作,其余与1进行“按位与”操作即可。例:把整型变量a的高八位清0,保留低八位。方法是:把a和一个高八位为0,低八位为1的数进行按位与运算。程序清单如下:main(){inta=268,b=0x00ff,c;c=a&b;printf("a=%d,b=%d,c=%d\n",a,b,c);}运行结果:a=264,b=255,c=13(2)测试指定位的值:要判断某一指定位的值是否为1或0,只需将这一位与1进行“按位与”操作,然后判断结果是否为1或0即可。例:设x是一个字符型变量(8位二进制位),判断x的最低位是否为1。方法是:把x和0x01进行“按位与”运算,如果结果为1则x的最低位是1。x=********&00000001结果:0000000*。程序清单如下:main(){intx=268,y=0x001,z;z=x&y;printf("x=%d,y=%d,z=%d\n",x,y,z);}运行结果:x=268,y=1,z=0应当注意:“按位与”运算&的优先级低于关系运算符!、=和==,所以在判断结果是否为零时,表达式(x&0x01)!=0中的圆括号不能省略。(3)获取指定位的值:要想获取某些位的判断某些位的值,只需将这些位的与1进行“按位与”操作,其余与0进行“按位与”操作。比如,设a=00101101,想取出a中的2~5位,方法是:令a&00011110。结果为:00001100。例:设x是一个整型变量(16位二进制位),获取x的低8位。方法是:将x与数0x00ff进行按位与运算:设x=****************&0000000011111111结果:00000000********。最后的结果是保存了x的低八位。程序清单如下:main(){intx=268,y=0x00ff,z;z=x&y;printf("x=%d,y=%d,z=%d\n",x,y,z);}运行结果:x=268,y=255,z=1211.2.3按位或运算按位或运算符是指参与运算的两个数对应的二进制位进行逻辑或的操作,用“|”表示。1、按位或运算符的运算规则按位或运算符的运算规则:当两个数对应的位全为0时,得到的该位就为0,只要对应的位有一个1,得到的该位就为1。按位或运算可能的运算组合及其运算结果如下所示:0|0=01|0=10|1=11|1=1例如,x=0000000000001011,y=0000000000001010,则表达式x|y的计算结果如下:结果为十进制11。2.按位或运算的主要应用按位或运算的主要应用:按位置1。只要把需要置1的位与1进行“按位或”的操作,其余与此0进行“按位或”的操作。例:设x是一个整型变量,要求将x的低八位置1。方法是x=****************|0000000011111111结果:********11111111最后的结果是将x的低八位置1。程序清单如下:main(){intx=268,y=0x00ff,z;z=x|y;printf("x=%d,y=%d,z=%d\n",x,y,z);}11.2.4按位异或运算按位异或运算符是指参与运算的两个数对应的二进制位进行逻辑按位异或的操作,用“∧”表示。1、按位异或运算符的运算规则按位异或运算符的运算规则:若两个运算对象的对应二进制位不同,则结果的对应数位为1,否则为0。按位异或运算可能的运算组合及其运算结果如下所示:0∧0=01∧0=10∧1=11∧1=0例如,x=0000000000001011,y=0000000000001010,则表达式x∧y的计算结果如下:又如:c=10^610:0000,0000,0000,1010&6:0000,0000,0000,0110c:0000,0000,0000,1100(12)2.按位异或运算的主要应用按位异或运算的主要应用:特定位翻转和保留原值。(1)特定位翻转方法:特定位与1异或。对某些位进行操作,如该位为1则将它变为0,如该位为0则将它变为1。例如:设a是一个字符型变量,现要求将a的低4位翻转。a=01100110^00001111结果:01101001最后的结果是将a的低4位翻转。(2)保留原值方法:与0异或。例如:设a是一个字符型变量,现要求将a的低4位保留原值。a=01100110^00000000结果:01100110最后的结果是将a的低4位保留原值。(3)不用临时变量,实现交换两个变量的值。例:将一个整数的低4位,如果是1变为0,如果是变为1。#include"stdio.h"main(){inta,b=0xf,c;printf("请输入一个十六进制数a:\n");scanf("%x",&a);c=a^b;/*将a和b进行按位异或运算,其结果存入c*/printf("翻转后的数为:%x\n",c);getch();}11.2.5左移运算左移运算符是把“<<”符号左边的运算数的各二进制位全部左移若干位,移动的若干位由“<<”符号右边的数指定,高位丢弃,低位补0,用“<<”表示。1、左移运算符的运算规则左移运算符的运算规则:将运算对象中的每个二进制数位向左移动若干位,从左边移出去的高位部分被丢弃,右边空出的低位部分用“0”补齐。例如:x=0000000000001011,则x<<2的结果为0000000000101100。又例如:左移运算举例:chara=30*2^3;a=a<<2;结果如下:(30)=(0001,1110)(二进制)120)=(0111,1000)(二进制)注意:

若移出的高位部分不包含数位1,则每左移1位,相当于乖2,左移n位相当于乖2的n次方。若对c=44(00101100)进行下面的操作:

c=c<<1;c的值变为88(01011000)

c=c<<1;c的值变为176(10110000)11.2.6右移运算右移运算符把运算符左边的运算数的各二进制位全部右移若干位,用“>>”表示,移动的若干位由“>>”符号右边的数指定。右移运算符的运算规则:将运算对象中的每个二进制数位向右移动若干位,从右边移出去的低位部分被丢弃,左边空出的高位部分的处理分两种情况。对无符号数和正数来讲,左边空出的高位部分补“0”;对负数来讲,左边空出的高位部分补“0”还是补“1”,与所使用的编译程序有关,有的编译程序补“0”,称为逻辑右移,有的编译程序补“1”,称为算术右移。例如:chara=0x78;a=a>>2;120/2^3结果如下:16进制78=120=(0111,1000)(二进制)右移后为:(30(0001,1110)(二进制)应当注意:(1)若移出的位全为0,则每右移1位,相当于除2,右移n位相当于除2的n次方。(2)当进行右移运算时,操作结果与操作数是否带符号有关。v 无符号操作数右移时,左端出现的空位补0,右端移出的数据舍去。v 带符号操作数右移时,左端出现的空位补符号位。若符号位为0则左边也是移入0,若符号位为1则左端也是移入1,移出的数据舍去。例如:带符号数a=

16和无符号数b=240,进行下列操作:a=a>>1;a的值变为

8(11111000)b=b>>1;b的值变为120(01111000)a=a>>1;a的值变为

4(11111100)b=b>>1;b的值变为60(00111100)11.3位域在程序设计中,有时存储一个信息不必用一个或多个字节,可以在一个字节中存放一个或多个信息。例如,“真”或“假”用1或0表示,只需一位即可,如果用一个变量来存储,则将浪费存储空间。为了解决该问题,C语言提供了位段操作。在前面介绍的位与运算、位或运算、位异或运算、反运算、左移运算、右移运算等几种的综合运算,可以实现对某一位或某几位的存取,但较麻烦。c语言中允许在结构体中以位为单位来指定其成员所占的内存长度,这种以位为单位的成员就称为位段或位域(bitfield)。所谓位段是由一个或多个二进制数位组成的,它是数据的一种压缩形式。位段是一种特殊的压缩形式结构体结构中的成员,它的特殊性在于它是以位为单位定义长度的。11.3.1位域或位段(bitfield)的定义形式c语言中允许在结构体中以位为单位来指定其成员所占的内存长度,这种以位为单位的成员就称为位段或位域(bitfield)。所谓位段是由一个或多个二进制数位组成的,它是数据的一种压缩形式。位段是一种特殊的压缩形式结构体结构中的成员,它的特殊性在于它是以位为单位定义长度的。11.3.1位域或位段(bitfield)的定义形式位域或位段(bitfield)的定义形式如下:struct位域结构体名{位域列表}其中,位域列表的形式为:类型说明符位域名:位域长度;其中,位域名的类型必须指定为unsignedint型或int型,一般为unsigned型。位域长度以二进制位为单位。例如:structbs{unsignedinta:1;unsignedintb:3;unsignedintc:4;}bit,*pbit;定义了结构体bs,该结构体变量共有3个成员,其中a,b,c成员是位段,分别占1位、3位、4位,共占1个字节。又如:structwd{unsigneda:2;unsignedb:3;unsignedc:6;

unsignedd:4;intk;}dat;定义了结构体wd,该结构体变量共有5个成员,其中a、b、c、d成员是位段,分别占2位、3位、6位、4位,k是的一般成员,k占2个字节。11.3.2位域的引用位域的引用方法与引用结构体变量中的成员相同,即:位域结构体名.位域名在C语言中,可以通过赋值语句给位域赋值。例如:structbs{unsineda:6;intb:2;intc:8;}data;这里定义一个位域结构bs,同时定义了data为bs变量,共占两个字节。其中位域a占6位,b占2位,c占8位。位域中数据的引用为:data.a=7;data.b=1;data.c=9;注意:1、赋值时不能超过位域允许的最大值范围,如data.b只占2个位,最大值为3,此时若把8(二进制为1000)赋给它,就会自动取赋予该数的低位,也是就00,最终data.b的值为0。2、位域还可以用整型格式符输出。例如:printf(“%d,%d,%d\n”,data.a,data.b,data.c);也可以用%u、%o、%x等格式符输出。11.4位运算应用举例例:从键盘上输入一个正整数n,判断此数是奇数还是偶数。分析:奇数的二进制表示中右边的第1位为1,偶数的二进制表示中右边的第1位为0。因此该题就转换为取该数右边的第1位,并判断其值是否为0。程序清单如下:main(){intn;printf("请输入一个大于0的数n:");scanf("%d",&n);if((n&0x01)==0)/*取n的最后一位,若其值为0,则为偶数,否则为奇数*/printf("%d是一个偶数。\n",n);elseprintf("%d是一个奇数。\n",n);getch();}例:将十六进制数转换为二进制数。分析:人们有时希望知道某个十六进制数的二进制数是什么,但C语言的printf()函数只提供%x,%d,%o方式输出一个整数(即十六进制,十进制,八进制)而不能直接输出一个整数的二进制形式,需要人工转换,很不方便。在这里可以用位运算来实现此功能。采用的方法是:对一个整数num(16位)的每一位进行测试,视其为0还是为1,可以设置一个屏蔽字与该数进行&运算,从而保留(取出)所需的一个位的状态。从高低(第15位)开始,此

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论