1、 程序设计技术基础-C语言第十一章 位 运 算 11.1 数字系统、位和字节 11.2 位运算符与位运算 11.3 位运算应用程序举例 11.4 位 段2022-8-82程序设计技术基础-C语言11.1 数字系统、位和字节 11.1.1 数字系统 数制也称计数制,是用一组固定的符号和统一的规则来表示数值的方法。按进位的方法进行计数,称为进位计数制。如在日常生活中使用的十进制,在计算机中采用的二进制,以及八进制、十六进制等都是进位计数制。一种进位计数制包含一组数码符号和两个基本要素:基数和位权。2022-8-83程序设计技术基础-C语言 1数码 数码是指数制中表示基本数值大小的不同符号。例如 十
2、进制有10个数码:0、1、2、3、4、5、6、7、8、9。二进制有2个数码:0、1。八进制有8个数码:0、1、2、3、4、5、6、7。十六进制有16个数码:09和A、B、C、D、E、F。2022-8-84程序设计技术基础-C语言 2基数 基数是指数制所使用数码的个数。例如,二进制的基数为2;十进制的基数为10。在运算中,当某一位上达到或超过基数大小时,就会向前进一。如十进制满十进一,二进制满二进一,十六进制则满十六进一。2022-8-85程序设计技术基础-C语言 3位权 位权是指数制中每一固定位置对应的单位值。一个数据在某个位置上的值等于该数字与这个位置上的因子的乘积,而该因子的值是由所在位置
3、相对于小数点的距离来确定的,这个因子就是位权,即各进位制中位权的值是基数的若干次幂。例如:十进制的123:1的位权是102=100,2的位权是101=10,3的位权是100=1;二进制中的 1101,第一个1的位权是23=8,第二个1的位权是22=4,0的位权是21=2,第三个1的位权是20=1。2022-8-86程序设计技术基础-C语言 任意的R进制数N按位权展开形式如下:其中:ri为计数制中任一个数码,R为基数。为了区分不同数制的数据,可以用括号加基数下标表示数据所属的数制。如:十进制数309.84的位权展开式为:(309.84)10=3102+0101+9100+810-1+410-2
4、二进制数11011.01 的位权展开式为:(11011.01)2=124+123+121+120+12-22022-8-87mmnnnnnmiiiRrRrRrRrRrRrRr.N11001122111程序设计技术基础-C语言11.1.2 位和字节 在计算机中,表示信息的单位有位、字节、兆、吉等,它们是表示信息量大小的基本概念。1位(bit)位,音译为“比特”,是计算机内构成信息的最小数据单位,即一个1或0。一般用小写字母“b”表示。一位二进制可表示21=2个信息,如:是或否,有或无,真与假等。2022-8-88程序设计技术基础-C语言 2字节(Byte)字节是计算机数据存储和处理信息的基本数据
5、单位。简记为“B”规定1个字节为8位,即8个二进制位是一个字节。1B=8b。2022-8-89程序设计技术基础-C语言 存储器的存储容量除了以位、字节为单位来度量外,还需要一些更大的单位,有KB、MB、GB、TB等度量单位:1KB=210B=1024B (K代表“千”)1MB=220B=210210B=10241024B (M代表“兆”)1GB=230B=210210210B=102410241024B (G代表“吉”)1TB=240B=210210210210B=1024102410241024B (T代表“太”)2022-8-810程序设计技术基础-C语言11.2 位运算符与位运算 C语言
6、的位运算可以分为位逻辑运算与位移位运算,共计6种基本位运算符:注:(1)位运算符中,除是单目运算符外,其余均为双目运算符;(2)运算量只能是整型或字符型的数据,不能为实型数据2022-8-811运算符运算符含义含义运算符运算符含义含义&按位与按位与|按位或按位或按位异或按位异或按位取反按位取反右移右移程序设计技术基础-C语言11.2.1 位逻辑运算符与运算 1“按位与”运算(&)“按位与”是指参加运算的两个数据,按对应的二进制位分别进行“逻辑与”运算。如果两个相应的二进制位都为1,则该位的运行结果为1(真);否则为0(假)。0&0=0;0&1=0;1&0=0;1&1=12022-8-812程序
7、设计技术基础-C语言 例如:13&10=?00001101 (=13)(&)00001010 (=10)00001000 (=8)2022-8-813程序设计技术基础-C语言“按位与”运算有一些特殊的用途:2022-8-814(1 1)清零:清零:若想将某个二进制数的指定位清零,可将待清零位与若想将某个二进制数的指定位清零,可将待清零位与0 0进行进行“按位与按位与”运算,其余位与运算,其余位与1 1进行进行“按位与按位与”运算;运算;若想将该数各位都清零,可使其与零进行若想将该数各位都清零,可使其与零进行“按位与按位与”运算。运算。【例例11-611-6】将字符变量将字符变量chch所占的字
8、节单元清零。所占的字节单元清零。程序设计技术基础-C语言【例11-611-6】将字符变量chch所占的字节单元清零。程序如下:#includeint main()char ch=67;printf(ch=%d n,ch);ch=ch&0;printf(ch&0后ch=%d n,ch);return 0;2022-8-815程序运行结果为:ch=67ch&0后ch=0程序设计技术基础-C语言(2)保留指定位:若想保留某个二进制数中的指定位。可将指定位与1进行“按位与”运算,其余位与0进行“按位与”运算即可实现。例如对一个十六位二进制整数a,若想要将其高八位清0,而保留其低八位。则进行:a&000
9、00000 11111111 运算即可:00000001 00110100 (a=308)(&)00000000 11111111 (=255)00000000 00110100 (=52)2022-8-816程序设计技术基础-C语言2“按位或”运算(|)按位或”是指参加运算的两个数据,按对应的二进制位分别进行“逻辑或”运算。如果两个相应的二进制位都为0,则该位的运算结果为0(假);否则为1(真)。即:0|0=0;0|1=1;1|0=1;1|1=1 例如13|10的运算为:2022-8-817 00001101 (=13)(|)00001010 (=10)00001111 (=15)程序设计技
10、术基础-C语言“按位或”运算的一大用途是经常用来对一个数据的某些位置1。【例11-7】将一个8位的二进制整数的低4位置1,高4位不变。2022-8-818程序如下:程序如下:#includeint main()char x=67;printf(“x初值为%dn”,x);x=x|15;printf(“x|15运算后的值为%dn”,x);return 0;程序运行结果为:程序运行结果为:x初值为初值为67x|15运算后的值为运算后的值为79程序设计技术基础-C语言3“按位异或”运算()“按位异或”是指参加运算的两个数据,按对应的二进制位分别进行“逻辑异或”运算。如果两个相应的二进制位为“异”(值不
11、同),则该位的运算结果为1(真);否则运算结果为0(假)。即 00=0;01=1;10=1;11=0 例如:1310的运算为:2022-8-819 00001101 (=13)()00001010 (=10)00000111 (=7)程序设计技术基础-C语言“按位异或”运算有以下用途:(1)保留原值:与0进行“按位异或”运算,可保留原值。即:a0=a。例如:130的运算为:00001101 (=13)()00000000 结果为:00001101 2022-8-820程序设计技术基础-C语言(2)使特定位翻转:与1进行“按位异或”运算,可使操作数特定位进行翻转,即由0变1或者由1变0。2022
12、-8-821程序如下:#includeint main()char x=l;printf(“l=%dn”,x);x=x15;printf(x15=%dn,x);return 0;【例例11-811-8】设字符设字符x=lx=l,将其二,将其二进制数的高进制数的高4 4位保位保留原样,低留原样,低4 4位各位各位翻转。位翻转。01101100 (=108)()0000 1111 (=15)0110 0011 (=99)程序运行结果为:l=108x15=99程序设计技术基础-C语言(3)置零:每一个数与它自身进行“异或”运算,结果各位均为零。即:xx=0。2022-8-8224“按位取反”运算()
13、按位取反”运算符“”是唯一的一个单目位运算符,用来将一个二进制数的每一位取反,即将1(真)变0(假),将0(假)变1(真)。即0=1;1=0程序设计技术基础-C语言按位取反”运算常用来生成与系统实现无关的常数,以增加程序的可移植性。如要将变量如要将变量x=103=x=103=(11001111100111)2 2最低最低6 6位置成位置成0 0,其余位不变。,其余位不变。用用“按位与按位与”运算实现,就需要考虑运算实现,就需要考虑x x在系统内存放的位数:在系统内存放的位数:如果如果x x占占2 2个字节,则需要执行:个字节,则需要执行:x=x&0 xffc0 x=x&0 xffc0 如果如果
14、x x占占4 4个字节,则需要执行:个字节,则需要执行:x=x&0 xffffffc0 x=x&0 xffffffc0 但若果把表达式变为:但若果把表达式变为:x x=x x&0 x3f0 x3f 整数整数x x占占2 2个字节还是占个字节还是占4 4个字节都能实现要求,大大增强了程序个字节都能实现要求,大大增强了程序的可移植性。的可移植性。2022-8-823程序设计技术基础-C语言11.2.2 位移位运算符与运算 1“左移”运算()左移运算符“”是双目运算符,左移运算的一般形式为:运算对象左移位数。左移的作用是将一个数的各二进制位依次左移若干位(由左移位数给出),左移时,右端(低位)补0,
15、左端(高位)移出的部分舍去。2022-8-824程序设计技术基础-C语言 例如,假设以一个字节存一个整数,则无符号整型变量a=15,在执行a=a2后,a的值变为60。左移变化过程如下图:可见,左移1位相当于操作数乘以2,左移2位相当于操作数乘以4,左移n位相当于操作数乘以2n,此外,左移运算要比乘法快的多。但此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况。2022-8-8250000 11110000 11110001 11100001 11100011 11000011 1100左移一次左移一次左移一次左移一次程序设计技术基础-C语言 例如:若变量a=65,即二进制数(010000
16、01)2时,左移一位时溢出的是0,变为(10000010)2,即130。而左移2位时,溢出的高位中包含1,a的值变为(00000100)2,即4,则不符合上述结论。【例11-9】输入两个数字符a和b,由a、b组合生成整数c(c用字符类型表示),并显示出来。生成规则是:a的低4位作为c的高4位,b的低4位作为c的低4位。2022-8-826程序设计技术基础-C语言#include int main()char a,b,c;while(1)printf(Please input a and b:n);scanf(%c,%c,&a,&b);if(a=0)&(b=0)break;a=a)右移运算符“”
17、是双目运算符,右移运算的一般形式为:运算对象右移位数 右移的作用是将一个数的各二进制位依次右移若干位(由右移位数给出),右移时,右端(低位)移出的部分舍去,左端(高位)移入的二进制数分两种情况:对于无符号数和正整数,高位补0;对于负整数,有的系统高位补1,有的系统高位补0。补0的称为“逻辑右移”,即简单右移;补1的称为“算术右移”。具体情况需要查阅相应C编译程序用户手册。2022-8-828程序设计技术基础-C语言 例如,占一个字节的无符号整型变量a=15,则a=a2后,a的值变为3(向下取整)。变化过程如图11-2所示。可见,右移1位相当于操作数除以2,右移2位相当于除以4,右移n位相当于操
18、作数除以2n。但此结论只适用于该数为无符号数和正整数。2022-8-8290000 11110000 11110000 01110000 01110000 00110000 0011右移一次右移一次右移一次右移一次程序设计技术基础-C语言【例11-10】取一个无符号整数a(16位)从右端开始的47位,重新构成一个数。分析:设a=(00000000 11011001)2,其从右端开始的47位依次为1101,需要单独提取出来构成一个新数。2022-8-830程序如下:#includeint main()unsigned a,b,c,d;printf(“Please input an octal n
19、umber:”);scanf(%d,&a b=a4 c=(0=和=。它们和复合赋值运算符的运算规则相似,结合方向从右向左,即把左边值与右边值位运算之后赋值给左边变量。例如:a&=0 x19等价于 a=a&0 x19 a=2等价于a=a22022-8-831程序设计技术基础-C语言 注意:不同类型的整数数据(即数据长度不同)在进行混合类型的位运算时,系统会按右端对齐原则进行处理,按数据长度大的数据进行处理,将数据长度小的数据左端补0或1。例如char a与int b进行位运算时,按int 进行处理,char a转化为整型数据,并在左端补0。补位原则如下:(1)对于有符号数据:如果a为正整数,则左
20、端补0,如果a 为负数,则左端补1。(2)对于无符号数据:在左端补0。2022-8-832程序设计技术基础-C语言 位运算符优先级排列表2022-8-833优先级优先级位运算符位运算符优先级优先级位运算符位运算符1425|3&6&=、=、|=、=程序设计技术基础-C语言11.3 位运算应用程序举例【例11-11】从键盘输入一个整数,判断此数的奇偶性。分析:对一个二进制数而言,其最低一位为0时,就是偶数,否则为奇数。因此可利用“按位与”运算的保留指定位功能,将其二进制最后一位提取出来,加以判断是0还是1。2022-8-834#includeint main()int a;printf(Pleas
21、e input a number:);scanf(%d,&a);if(a&0 x01)=0 printf(%d 是偶数!n,a);else printf(%d是奇数!n,a);return 0;程序运行结果为:Please input a number:1515是奇数!程序设计技术基础-C语言【例11-12】不用临时变量,交换两个字符变量的值。分析:这是一个经典的问题,交换变量的值,一般需要一个中间变量。然而利用“按位异或”运算中的位翻转特性,可以在没有中间变量的情况下实现整数间的互换。2022-8-835#includeint main()char a=12,b=10;printf(“原数为
22、a=%d,b=%dn”,a,b);a=ab;b=ba;a=ab;printf(“交换后为a=%d,b=%dn”,a,b);return 0;程序运行结果为:原数为a=12,b=10交换后为a=10,b=12程序设计技术基础-C语言【例11-13】从键盘上输入一个十进制整数,统计该整数所对应的二进制数中1的个数(设整数占两个字节)。分析:统计一个整数m的二进制数中1的个数,可以利用“按位与”运算判断最后一位是否为1,然后再利用“右移”位运算,将m中的每一位依次移至最后一位进行上述判断,直至结束。2022-8-836#includeint main()int i,count,m;printf(Pl
23、ease input m:);scanf(%d,&m);count=0;for(i=0;i1;printf(Numbers of 1 in m is%dn,count);return 0;程序运行结果为:Please input m:15Numbers of 1 in m is 4程序设计技术基础-C语言【例11-14】循环移位。将十六进制数a进行循环右移,即a的二进制数的右端n位移到最左端n位。如:原数a=(12345678)16,循环右移4位后为(81234567)16.分析:这里不能直接使用运算符,因为,运算符在左面添0或添1不确定。所以要用左移与右移组合使用以达到目的。设整数a=0 x
24、12345678,内存占4个字节,循环右移n=4位(二进制位)。2022-8-837#includeint main()unsigned a,b,c;int n;printf(请输入需要移动的数据:a=);scanf(%x,&a);printf(请输入需要移动的位数:n=);scanf(%d,&n);b=an;c=c|b;printf(“%xn”,c);return 0;程序运行结果为:请输入需要移动的数据:a=12345678请输入需要移动的位数:n=481234567程序设计技术基础-C语言11.4 位 段 计算机所能表示的信息的最小单位是一个字节,即8位。事实上在计算机用于过程控制、参数
25、检测或数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,例如,描述“真”或“假”时,通常用1表示“真”,0表示“假”,只需1位即可,而不需要占用8位甚至更多。为了有效的利用存储空间,提高效率,在C 语言中,提供了一种特有的压缩信息的数据结构位段。2022-8-838程序设计技术基础-C语言 位段(bit-field)是以位为单位来定义结构体中的成员变量所占的存储空间的长度。含有位段的结构体称为位段结构。位段结构也是一种结构体类型,与一般结构体在形式与用法上是很相近的。只不过其中含有以位为单位定义存储长度的整数类型位段成员。采用位段结构既节省存储空间,又可方便操作。2022-8-8
26、39程序设计技术基础-C语言11.4.1位段结构类型 1位段结构类型定义 C语言中的位段是以“位”为单位来定义结构体中的成员长度的。其定义格式为:struct 位段结构类型名 类型说明符1 位段名1:位段1占用位数;/*最低位*/类型说明符2 位段名2:位段2占用位数;/*次低位*/;类型说明符n 位段名n:位段n占用位数;2022-8-840程序设计技术基础-C语言例如:struct packed_flagunsigned int f1:1;unsigned int f2:1;unsigned int f3:1;unsigned int type:4;unsigned int index:9
27、;2022-8-841说明:该例中,定义了一个位段结构 packed_flag。该结构定义了五个位段成员,均为unsigned int 类型的。前三个位段依次叫做 f1、f2和f3,各占1 位;位段 type 占有 4 位;位段 index 占有 9 位。C 编译器自动把上面的位段定义压缩在一起,这样结构packed_flag类型总共使用了 16 位,即2个字节。程序设计技术基础-C语言位段定义注意事项(1 1)位段的类型只能是)位段的类型只能是intint或或unsignedunsigned类型,不能是类型,不能是charchar型或型或者浮点型;者浮点型;(2 2)在位段结构中还可以定义无
28、)在位段结构中还可以定义无名位段。无名位段起位段之间的名位段。无名位段起位段之间的分隔作用。无名位段不能被访问,分隔作用。无名位段不能被访问,但是会占据空间。但是会占据空间。例如:2022-8-842struct packed1 unsigned f1:4;unsigned f2:1;unsigned :2;/*无名位段,起分隔作用无名位段,起分隔作用*/unsigned f3:1;f1 f2 f3 4121f2后面的无名位段占据2位,但其空间不用程序设计技术基础-C语言(3)一个位段必须存储在同一存储单元,不能横跨两个存储单元。如果一个单元空间不够,则系统从下一个单元起存放该位段。(上述“存
29、储单元”可能是一个字节,也可能是2个字节,视不同的编译系统而异)。假设现在的“存储单元”是2个字节,则下列位段定义:2022-8-843假设现在的“存储单元”是2个字节,则下列位段定义:struct packed2 unsigned f1:8;unsigned f2:4;unsigned f3:6;unsigned f4:2;一个存储单元一个存储单元另 一 个 存另 一 个 存储单元储单元程序设计技术基础-C语言(4)长度为0的无名位段,可以强制其下一个位段到下一个存储单元存放。例如:struct packed3unsigned f1:4;unsigned f2:2;Unsigned:0;un
30、signed f3:2;2022-8-844一个存储单元一个存储单元另一个存储单元另一个存储单元在这个位段定义中,在这个位段定义中,f1f1、f2f2和和f3f3共需要共需要8 8位即可,位即可,但因为但因为f2f2和和f3f3之间的之间的0 0长长度位段的存在,度位段的存在,f3f3只能存只能存入下一个存储单元中。入下一个存储单元中。程序设计技术基础-C语言(5)在位段结构体中,不一定必须是位段成员,也可以包含非位段成员。例如:struct packed4 unsigned f1:4;unsigned f2:4;unsigned f3:4;int n;/*非位段成员*/data4;2022-
31、8-845程序设计技术基础-C语言11.4.2位段结构类型变量的定义与引用 1定义位段结构类型的变量 位段结构类型变量的定义方法和其它结构类型变量定义方法一样。(1)先声明位段结构类型再定义变量。例如利用上面已经定义好的位段结构类型packed_flag来定义变量data的语句为:struct packed_ flag data;位段结构类型名 变量名;2022-8-846程序设计技术基础-C语言(2)在声明位段结构类型的同时定义变量。其一般形式为:struct 位段结构体名成员列表变量名列表;例如上述位段结构类型变量data的定义语句也可写成:2022-8-847struct packed_
32、flag unsigned int f1:1;unsigned int f2:1;unsigned int f3:1;unsigned int type:4;unsigned int index:9;data;程序设计技术基础-C语言 2位段成员的引用 定义位段结构类型的变量后,就可以如引用一般结构体成员一样方便的引用位段成员:位段变量名.位段名 例如由位段结构packed_flag定义了位段变量data后,各位段就可以有如下引用:data.f1=0;data.f2=1;data.index=data.f1+10;2022-8-848程序设计技术基础-C语言 3位段引用时的注意事项(1)所赋值
33、超过了位段所允许的最大范围,系统会自动取数的低位。(2)位段可以在表达式中被引用,并被系统自动转换成整型数。例如下面的表达式是合法的:data.f1+data.f2*2(3)位段可以以整型格式输出。例如:printf(“%d,%d”,data2.f1,data1.f2);2022-8-849程序设计技术基础-C语言4位段引用举例【例11-15】请用三角形三边边长构造一个位段结构类型,并用其判断给定的三边边长能否构造成一个三角形。2022-8-850#include struct triangle unsigned a:10;unsigned b:10;unsigned c:10;int mai
34、n()struct triangle tr;printf(“sizeof(triangle)=%dn”,sizeof(tr);tr.a=3;tr.b=4;tr.c=5;if(tr.a+tr.b tr.c|tr.a+tr.c tr.b|tr.b+tr.c tr.a)printf(“The three sides of a triangle are:a=%d,b=%d,c=%dn,tr.a,tr.b,tr.c);else printf(无法构成三角形n);return 0;程序运行结果为:sizeof(triangle)=4 The three sides of a triangle are:a=
35、3,b=4,c=5程序设计技术基础-C语言2022-8-8511、有关数制的相关知识以及计算机中信息的计量单位。2、C语言6种位运算符以及具体运算规则:(1)按位与(&)运算:可以用来对数据清零、提取或保留二进制数指定位以及判断数据的奇偶性等;(2)按位或(|)运算经常用来将二进制数的某些位变为1;(3)按位异或()运算可以翻转特定位以及与0异或保留原值、与它自身异或置零;本章小结程序设计技术基础-C语言2022-8-852(4)按位取反()运算常用来生成与系统实现无关的常数,以增加程序的可移植性;(5)左移()运算中,右移n位相当于操作数除以2n。3、位段特殊形式的结构体,它是以“位”为单位来定义结构体中的成员长度的,既能够节省空间,又便于操作。注意本章节知识点!