《第9章位运算.ppt》由会员分享,可在线阅读,更多相关《第9章位运算.ppt(38页珍藏版)》请在三一文库上搜索。
1、第9章 位运算,教学目的: 通过本章的学习,要求能理解二进制位运算操作和位段结构,能熟练使用位运算符进行程序设计,学习位操作能够为硬件平台的程序设计奠定基础,为后续课程的学习起到铺垫作用。,第9章 位运算,结构和内容,第9章 位运算,重点和难点 重点: (1) 位逻辑运算 (2) 移位运算 (3) 复合赋值位运算 (4) 不等长数据的位运算 (5) 位段的结构、存储及使用 难点: (1) 不等长数据的位运算 (2) 位段的结构、存储及使用,9.1 位运算的C程序实例,位运算引例 【例9.1】一个简单的位运算C程序 /* 源文件名:Li9_1.c 功能:从键盘输入两个整数a和b,分别对其进行位运
2、算。 */,#include void main() int a,b; int e,f,g,h,i; puts(“请输入整数a和b:“); /*打印输出一串字符串*/ scanf(“%d%d”, ,9.2 二进制位运算,9.2.1 位逻辑运算,位操作是对字节或字节内的二进制位进行测试、设置 或逻辑的运算。位操作可以分为两类:一类是位逻辑运算, 另一类是移位运算。,位逻辑运算用来对某一个或某一对二进制位进行操作,其运算符有以下几个: 表示按位取反 &表示按位与 表示按位或 表示按位异或 除了是一元运算符外,&、都是二元运算符。位逻辑运算的运算对象是整数。,位逻辑运算规则与逻辑运算(&、!)一样,
3、也可用真值表表示。设a、b分别表示一个二进制位,则按位逻辑运算的真值表可表示成如表9-1所示的形式。,表9-1 逻辑运算符的运算规则,按位与运算 按位或运算 按位异或运算 按位取反运算,9.2.1 位逻辑运算,按位与运算,按位与逻辑运算的运算规则是:只有对应的位均为1时,与运算的结果才为1,其他的情况均为0。即: 0&0=0 0&1=0 1&0=0 1&1=1 【例9.2】令a=10,b=8,c=a&b,求c的值。 c的内容可以通过下式运算: 00001010 00001000 00001000,/* 源文件名:Li9_2.c 功能:令a=10,b=8,c=a ,按位与运算的用途有以下几个方面
4、: 可以对某位进行清零操作。此时只需将需要清零的对应位与0位进行“按位与”操作即可。 例如:若将00010011的低4位清零,只需将其低4位与零相与,高4位与1相与即可,也就是进行以下的操作: 00010011 11110000 00010000 即将00010011与11110000进行与操作就可以满足要求。 可以提取某些位。此时只需将需要提取的位与1进行“按位与”操作即可。例如:保留1100011中的最高位,其余位清零,可用如下的操作: 11000110 10000000 10000000 则上述与操作完成后,1100011就变成了10000000,(&),(&),按位或运算,按位或运算的
5、运算规则是:只有按位或操作的对应位均为零时,结果才为零,其他情况按位或的结果均为1。即, 0|0=0 0|1=1 1|0=1 1|1=1 【例9.3】令a=12,b=9,c=a|b,求c的值。 c的内容可以通过下式运算: 00001100 00001001 00001101,/* 源文件名:Li9_3.c 功能:令a=12,b=9,c=a|b,求c的值。 */ #include void main() int a=12,b=9; int c; c=a|b; printf(“c=%dn“,c); ,按位或运算的用途主要是对某位进行置1操作,例如:将00100010的高四位置1,可以将其与1111
6、0000进行“按位或”运算。 具体如下: 00100010 11110000 11110010,( | ),按位异或运算,按位异或的运算规则是:参与按位异或运算的两个二进制位如果相同,则结果为0,如果不同则结果为1。即, 00=0 01=1 10=1 11=0 【例9.4】令a=10,b=8,c=ab,求c的值。 c的内容可以通过下式运算: 00001010 00001000 00000010,/* 源文件名:Li9_4.c 功能:令a=10,b=8,c=ab,求c的值。 */ #include void main() int a=10,b=8; int c; c=ab; printf(“c=
7、%dn“,c); ,按位异或运算主要有以下三个用途: 与0异或,可以保留原值。因为原数中的1与0进行异或运算得1,0与0进行异或运算得0。例如将035与00按位异或可以保留035。 具体如下: 00011101 00000000 00011101 将特定位翻转。例如:将10001111的高四位进行翻转,即1变成0、0变成1,则可以使用异或运算。具体如下:( ) 10001111 11110000 01111111,不用临时变量交换两个值。在以前的章节中介绍交换变量时,需要借助第三个临时变量来完成;而通过异或运算则不需要第三个变量即可以完成交换两个值的操作。 例如a=5,b=4,请用异或操作完成
8、a=4,b=5。具体如下: b=ab=101100=001 a=ab=101001=100 b=ab=100001=101 经过上述操作后即可完成交换a与b的值的操作,即 a=100=4,b=101=5。,按位取反运算,按位取反运算的运算规则是:0的按位取反结果为1,1的按位取反结果为0。即, 0=1 1=0 【例9.5】令a=10, c=a,求c的值。 c的内容可以通过下式运算:() 00001010 11110101,/* 源文件名:Li9_5.c 功能:令a=10, c=a,求c的值。 */ #include void main() int a=10; int c; c=a; print
9、f(“c=%dn“,c); ,位运算符的优先级是: 按位取反优先级最高,其次是按位与和按位异或,最低的是按位或。位运算与其他运算符之间的运算优先级和结合性参见附录中介绍。,9.2.2 移位运算,移位运算实现二进制位的顺序向左或向右移位。,左移位运算 右移位运算,左移位运算,左移位运算符是,其语法格式为: an 其中,a是操作数,可以是一个char型或整型的变量或表达式;n是待移位的位数,必须是正整数。功能是将a中所有的二进制位数向左移动n位。 左移位的运算规则是:在移位过程中,各个二进位顺序向左移动,右端空出的位补0,移出左端之外的位则被舍弃。例如,a=10,其二进制的存储形式为0000101
10、0,则a2表示将a的各个二进制位顺序左移2位:00101000,即十进制的40。 由左移位的规则可以看出,对于无符号数而言,左移位相当于乘2运算,左移n位相当于乘2的n次方。,右移位运算,右移位运算符是,其语法格式为: an 其中,a是操作数,可以是一个char型或整型的变量或表达式;n是待移位的位数,必须是正整数。功能是将a中所有的二进制位数向右移动n位。 右移位的运算规则是:在移位过程中,各个二进位顺序向右移动,左端空出的位补0还是补1取决于被移位的数是有符号数还是无符号数,具体为: 对于无符号数进行右移时,左端空出的位一律补0。 对于用补码表示的有符号数进行右移时,如果采用逻辑右移,则不
11、管是正数还是负数,左端空位一律补0;如果采用算术右移,则正数右移,左端的空位全部补0;负数右移,左端的空位全部补1(即符号位)。Turbo C采用的是算术右移。 例如,a=-32768,采用补码表示时,其二进制的存储形式为1000000000000000,则a2表示将a的各个二进制位顺序右移2位,Turbo C中采用算术右移,结果为:111000000000000000,即十进制的-8192。 根据右移位规则,采用算术右移相当于除2运算。右移一位相当于该数除以2,右移n位相当于该数除以2的n次方。,9.2.3复合赋值位运算符,位运算符可以和赋值运算符构成复合赋值位运算符。 复合赋值位运算符的形
12、式有:&=、|=、=、=、=。 【例9.6】复合赋值位运算的举例。 a=5,b=4,则a|=b相当于a=a|b=5|4=101|100=5。 c=8,d=9,则c&=d相当于c=c&d=8&9=1000&1001=8。 e=8,f=2,则e=f相当于e=ef=82=10002=100000=32。,/* 源文件名:Li9_6.c 功能:复合赋值位运算的举例。 */ #include void main() int a=5,b=4; int c=8,d=9; int e=8,f=2; a|=b; /*相当于a=a|b=5|4=101|100=5*/ c ,9.2.4不同长度的数据进行位运算,当参
13、加位运算的两个操作数的数据长度不等时,例如:一个int型的数据,另一个long型的数据,则两个数参加运算时,系统自动按右对齐。对于无符号数,系统在做对齐处理时,左端一律补0。对于有符号数来说,正数在做对齐处理时,左端补0;负数在做对齐处理时,左端补1。,9.3 位段,位段是由一个或几个二进制位组成的独立数据项。如果一个结构只含有整型的成员及位段成员,这种结构被称为位段结构。因此,位段结构只是结构的一个特例,有关结构的定义、引用、赋值、在函数间的传递等,都可以引申到位段结构中来,位段结构的特殊性就是其各个成员只能是整型的。因此,本节仅就位段成员方面的问题作一些说明。,9.3.1位段结构类型及位段
14、结构变量的定义,位段结构类型及位段结构变量的定义格式为: struct 结构标识符 数据类型 位段名1:位数; 数据类型 位段名2:位数; 数据类型 位段名n:位数; 位段结构变量表; 其中,各位段的数据类型必须是int、signed或unsigned;位数为1的位段只能用unsigned;每个位段名后紧跟一个冒号,冒号后面是该位段的位数。,对位段结构的定义应注意以下几点:,各个位段必须依次单独定义,不能把几个位段组织成数组。 每个位段的长度可以超过一个字节,但不能超过计算机的字长(在Turbo C 2.0中为16位),所有位段的总长度则可以超过一个计算机字长,超过的部分会占用下一个存储单元。
15、由于不允许一个位段跨越两个字长的存储单元,可定义一个长度为0的位段,以保证下一个位段从新的存储单元开始。例如: unsigned a:5; unsigned b:9; unsigned x:0; unsigned c:4; /*位段c将从下一个字长的存储单元开始存放*/ unsigned dt:3;,对位段结构的定义应注意以下几点:,如果位段结构的总长度不足n个计算机字长,余下的位可以定义一个不使用的位段或无名位段。例如,上面定义的8251A方式字位段结构中的dummy_bit就是一个不使用的位段,也可以定义如下的无名位段: unsigned :8; 这时,余下的8位将被清0。 位段结构变量可
16、以按位段初始化,初值表中,不需要初始化的位段用逗号跳过。 例如: struct bit word=3,1,2;,对位段结构的定义应注意以下几点:,位段结构中也可以包含整型的变量或数组成员,但变量或数组名后不能跟冒号和位数,系统自动将他们从新的存储单元开始存放。例如: struct a unsigned a1:2; unsigned a2:5; unsigned a3:4; int i; ch;,对位段结构的定义应注意以下几点:,结构中可以包含位段成员。 例如: struct employ char *number; char *name; float wage; unsigned lay_of
17、f:1; /*表示职工是否在岗*/ unsigned hourly:1; /*表示工资类别*/ unsigned deductions:3; /*表示工资折扣数*/ emp1; 比较emp1和上面的位段结构ch,可以看出,结构和位段结构可以交换使用,但必须注意,位段结构中不允许出现非整型的数据成员。,9.3.2位段结构的存储,位段结构中的所有成员按先后次序存放,但存储单元中位段的空间分配方向则随机而异。由于不同计算机的字长不同,造成使用位段结构的程序很难移植。下面以从左到右的空间分配方式,通过实例将位段结构存储分配中的几个问题说明如下:,每个位段结构变量有自己的起始地址,其中的每一个整型变量或
18、数组成员也有各自的地址,但位段成员则没有自己的地址,不能对位段成员进行取地址运算。 对于前面定义的位段结构变量ch来说,由于变量i必须从新的字节开始存放,因此系统自动在位段a3后面闲置5位。因此变量ch的存储格式为:,9.3.3位段结构的使用,【例9.8】位段成员的初始化、赋值和输出。 /* 源文件名:Li9_8.c 功能:位段成员的初始化、赋值和输出。 */ #include void main() struct bit unsigned a:1; unsigned b:2; unsigned c:3; int d; s=1,2,3,4; /*初始化*/ s.c=7; /*给s.c重新赋值7
19、*/ s.d=125; /*给s.d重新赋值125*/ printf(“%d %d %d %dn“,s.a,s.b,s.c,s.d); ,程序运行后,屏幕显示: 1 2 7 125 说明:一个位段所能存放的整数的范围与它的长 度有关,例如一个长度为3的 unsigned型位段能存放07。,小 结,位操作是对字节或字节内的二进制位进行测试、设置或逻辑的运算。位操作可以分为两类:一类是位逻辑运算,另一类是移位运算。 位逻辑运算用来对某一个或某一对二进制位进行操作,其运算符有以下几个: 表示按位取反 &表示按位与 表示按位或 表示按位异或 移位运算实现二进制位的顺序向左或向右移位。 位运算符可以和赋值运算符构成复合赋值位运算符。 复合赋值位运算符的形式有:&=、|=、=、=、=。 位段是由一个或几个二进制位组成的独立数据项。 位段结构中的所有成员按先后次序存放,但存储单元中位段的空间分配方向则随机而异。,
链接地址:https://www.31doc.com/p-3135571.html