1 / 43

C 语言程序设计

C 语言程序设计. 主讲:沈济南. TEL: 13971887071 E-mail: shenjinan@163.com. 第十九讲. 主讲内容: 第九章 位运算 9.1 位运算符与位运算 9.2 位段 9.3 程序设计举例. 9.1 位运算符与位运算. 9.1.1 位运算符. 9.1.2 按位取反运算符. 按位取反运算符“~”是一个单目运算符,能对一个二进制数的每一位都取反,即 0 变为 1 , 1 变为 0 。 例如: a= 0 0 0 1 1 0 1 0 /* 十六进制为 1a*/

Download Presentation

C 语言程序设计

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C语言程序设计 主讲:沈济南 TEL:13971887071 E-mail:shenjinan@163.com

  2. 第十九讲 • 主讲内容: • 第九章 位运算 • 9.1 位运算符与位运算 • 9.2 位段 • 9.3 程序设计举例

  3. 9.1 位运算符与位运算

  4. 9.1.1 位运算符

  5. 9.1.2 按位取反运算符 • 按位取反运算符“~”是一个单目运算符,能对一个二进制数的每一位都取反,即0变为1,1变为0。 • 例如: • a= 0 0 0 1 1 0 1 0 /*十六进制为1a*/ • ~ a= 1 1 1 0 0 1 0 1 /*十六进制为e5*/

  6. 9.1.3 左移运算符 • 左移运算符“<<”的功能是将一个数的各个二进制位全部向左平移若干位,左边移出的部分予以忽略,右边空出的位置补零。如: • a = 0 0 0 1 1 0 1 0 /*十六进制为1a*/ • a<<2 = 0 1 1 0 1 0 0 0 /*十六进制为68*/ • 一个数据,每左移1位相当于乘以2,左移2位相当于乘以4,以此类推。

  7. 9.1.4 右移运算符 • 与左移相反,右移运算符“>>”的功能是将一个数的各个二进制位全部向右平移若干位,右边移出的部分予以忽略,左边空出的位置对于无符号数补零,对于有符号数,若原符号位为0,则补0,若原符号位为1,则全补1。也就是右移后保持这个数的正负符号不变。 • 例如,若变量a被定义成unsigned char,即无符号型,则有: • a = 1 0 0 1 1 0 1 0 /*十六进制为9a*/ • a>>2 = 0 0 1 0 0 1 1 0 /*十六进制为26*/

  8. 若变量a被定义成char,即有符号型,则有: • a = 1 0 0 1 1 0 1 0 /*十六进制为9a*/ • a>>2 = 1 1 1 0 0 1 1 0 /*十六进制为e6*/ • 同样,一个数据每右移1位相当于除以2,右移2位相当于除以4,以此类推。

  9. 9.1.5 按位与运算符 • 运算符“&”将其两边数据对应的各个二进制位分别进行“与”运算,即二者都为1时结果为1,否则为0。如: • a = 1 0 1 1 1 0 1 0 /*十六进制为ba*/ • b = 0 1 1 0 1 1 1 0 /*十六进制为6e*/ • a&b = 0 0 1 0 1 0 1 0 /*十六进制为2a*/ • 可以发现,任何一位与1“与”运算时,结果保持原值,与0“与”运算时,结果皆为0。

  10. 如果参加&运算的是负数(如-3&-5),则以补码形式表示为二进制数,然后按位进行“与”运算。如果参加&运算的是负数(如-3&-5),则以补码形式表示为二进制数,然后按位进行“与”运算。 • 按位与有一些特殊的用途: • (1)清零。如果想将一个数的某些位清零,只要找一个二进制数,其中相应位为0,然后使二者进行&运算,即可达到清零目的。 • 如:原有数为00101011,现使它低四位清零。另找一个数,设它为10010000,低四位均为0。将两个数进行&运算:

  11. 00101011 • (&) 10010000 • 00000000 • 其道理是显然的。当然也可以不用10010000这个数而用其他数(如01000000)也可以。 • (2)保留一个数中某些指定位。如果想保留一个数中某些指定位,只要找一个二进制数,其中相应位为1,然后使二者进行&运算,即可达到目的。如有一个整数a(2个字节),想要其中的低字节。只需将a与(377)o按位与即可。

  12. 【例9.1】将一个十进制数转换为二进制数。 • 分析:C语言中printf函数提供的%x、%d、%o格式符可将一个整数以十六进制、十进制或八进制的形式输出,但没有二进制输出格式。人工转换的方法是设置一个屏蔽字,其中只有一位是1,其余各位均为0,与被转换数进行“与”运算,根据运算结果判断被测试的那一位是1还是0,其余二进位的测试方法相同。一个整数占4个字节,共有32个二进制位。

  13. /*源程序名:CH0901.C*/ • /*01*/ #include<stdio.h> • /*02*/ void main() • /*03*/ { • /*04*/ int i,bit; • /*05*/ unsigned int n,mask; • /*06*/ mask=0x80000000; /*最高位为1,其余位为0*/ • /*07*/ printf("enter your number:"); • /*08*/ scanf("%d",&n); • /*09*/ printf("binary of %d is:",n);

  14. /*10*/ for(i=0;i<32;i++) • /*11*/ { • /*12*/ bit=(mask & n)?1:0; • /*13*/ printf("%1d",bit); • /*14*/ mask=mask>>1; /*右移一位,得到下一个屏蔽字*/ • /*15*/ } • /*16*/ } • 程序运行过程: • enter your number: • 8↙ • binary of 8 is:00000000000000000000000000001000

  15. 9.1.6 按位或运算符 • 运算符“|”将两边对应的二进制位分别进行“或”运算,即二者之中只要有一个为1时结果就为1,两者都为0时结果才为0。如: • a = 1 0 0 1 1 0 1 0 /*十六进制为9a*/ • b = 0 1 0 1 0 1 1 0 /*十六进制为56*/ • a|b = 1 1 0 1 1 1 1 0 /*十六进制为de*/ • 可以发现,任何一位与0“或”时,其结果就等同于这一位。 • 按位或有一些特殊的用途: • (1)将一个数中某些指定位置1。

  16. 只要找一个二进制数,其中相应位为1,然后使二者进行或运算,即可达到目的。只要找一个二进制数,其中相应位为1,然后使二者进行或运算,即可达到目的。 • (2)保留一个数中某些指定位。如果想保留一个数中某些指定位,只要找一个二进制数,其中相应位为0,然后使二者进行或运算,即可达到目的。

  17. 9.1.7 按位异或运算符 • 按位异或运算符“^”的作用是判断两个相应位的值是否“相异”(不同),若为异,则结果为1,否则为0。如: • a = 1 0 0 1 1 0 1 0 /*十六进制为9a*/ • b = 0 1 0 1 0 1 1 0 /*十六进制为56*/ • a^b = 1 1 0 0 1 1 0 0 /*十六进制为cc*/ • 可以发现,任何一位与1“异或”时,其结果是将这一位取反,即由1变成0,或者由0变成1。 • 按位异或运算符的一些特殊的用途:

  18. (1) 使特定位翻转 • 假设有01111010,想使其低4位翻转,即1变为0,0变为1。可以将它与 • 00001111进行∧运算,即 • 01111010 • (∧) 00001111 • 01110101 • 结果值的低4位正好是原数低4位的翻转。要使哪几位翻转就将与其进行∧运算的该几位置为1即可。这是因为原数中值为1的位与1进行∧运算得0,原数中的位值0与1进行∧运算的结果得1。

  19. (2) 与0相∧,保留原值 • 如012∧00=012 • 00001010 • (∧)00000000 • 00001010 • 因为原数中的1与0进行∧运算得1,0∧0得0,故保留原数。 • (3) 交换两个值,不用临时变量 • 假如a=3,b=4。想将a和b的值互换,可以用以下赋值语句实现: • a=a∧b; • b=b∧a; • a=a∧b;

  20. 9.2 位段

  21. 9.2.1 位段结构体说明 • 位段结构体说明的一般形式为: • struct 位段结构体名 • { • unsigned int [位段名1]:k1; • unsigned int [位段名2]:k2; • …… • unsigned int [位段名n]:kn; • }; • 其中k1,k2,…,kn,一般是0—9中的一个数,表示某位段成员占的二进制位数(位段的宽度)。

  22. 例如: • structpacked-data • { • unsigneda:2; • unsignedb:6; • unsignedc:4; • unsignedd:4; • inti; • }data; • 其中a、b、c、d分别占2位、6位、4位、4位。i为整型。共占2个字节。也可以使各个位段不恰好占满一个字节。如:

  23. structpacked-data • { • unsigneda:2; • unsignedb:3; • unsignedc:4; • inti; • }; • structpacked-datadata; • 其中a、b、c共占9位,占1个字节多,不到2个字节。它的后面为int型,占2个字节。在a、b、c之后7位空间闲置不用,i从另一字节开头起存放。 • 位段成员的类型只能是int 或unsigned int;在每个字段说明的最后需要给出该字段的二进制位数,任一字段的位数不能超过一个字(一个int)的长度。

  24. 9.2.2 位段的引用 • 对位段的引用方法与引用结构体变量中的成员完全相同。 • 用位段结构体变量和成员访问运算符来引用位段。如: • x.a=10; x.c=2; • 注意:对位段赋值时,应不超过每一个位段能存储的最大值(由位段的宽度决定的,如上例中x.b的最大值为3,x.a的最大值为15),否则会溢出。 • 也可以用指针变量指向一个成员为位段的结构体变量,然后通过该指针变量来引用位段。如: • struct packed_data x, *p; • p=&x; /* 使p指向x */ p->a=10; p->c=2;

  25. 9.3 程序设计举例

  26. 【例9.2】按位异或运算可用来实现交换两个变量的值(并且不用第三个变量)。【例9.2】按位异或运算可用来实现交换两个变量的值(并且不用第三个变量)。 • /*源程序名:CH0902.C*/ • /*01*/ #include<stdio.h> • /*02*/ void main() • /*03*/ { • /*04*/ int a , b ; • /*05*/ a=10; • /*06*/ b=20; • /*07*/ printf(“a=%d\tb=%d\n”,a, b); • /*08*/ a=a^b; • /*09*/ b=b^a;

  27. /*10*/ a=a^b; • /*11*/ printf(“a=%d\tb=%d\n”,a, b); • /*12*/ } • 运行结果为:a=10 b=20 • a=20 b=10

  28. 【例9.3】机器中有一个机器字称为处理机状态字,它由若干字段组成,它反映处理机运行的状态。假设第5~7位是处理机的优先级,有时需要改变优先级,就必须取出第5~7位。设计一个程序取出处理机状态字的优先级。【例9.3】机器中有一个机器字称为处理机状态字,它由若干字段组成,它反映处理机运行的状态。假设第5~7位是处理机的优先级,有时需要改变优先级,就必须取出第5~7位。设计一个程序取出处理机状态字的优先级。 如下:(图)

  29. /*源程序名:CH0903.C*/ • /*01*/ #include<stdio.h> • /*02*/ void main() • /*03*/ { • /*04*/ unsigned int ps=0170360; • /*05*/ int p, n, t ; • /*06*/ p=7; /*开始位置*/ • /*07*/ n=3; /*位数*/ • /*08*/ ps=ps>>(p-n+1); /*将ps的5~7位右移到0~2位*/ • /*09*/ t=~(~0<<n); /*将3~15位置为0,0~2位置为1*/ • /*10*/ ps=ps&t; /*取出需要的位*/

  30. /*11*/ printf(“ps=%o\n”,ps); • /*12*/ } • 运行结果为: • ps=7

  31. 【例9.4】设计一个函数,通过调用函数read_modem ( ),从调制解调器端口读入一个字符,并将奇偶校验位置成0。 • 字节的位8是奇偶位,将该字节与一个位1到位7为1、位8为0的字节进行与操作,可将该字节的奇偶校验位置成0。表达式ch&127正是将ch中每一位同127数字的对应位进行与操作,结果c h的位8被置成了0。 • /*源程序名:CH0904.C*/ • /*01*/ char get_char_from_modem() • /*02*/ { • /*03*/ char ch;

  32. /*04*/ ch=read_modem(); /*从调制解调器端口中得到一个字符* / • /*05*/ return(ch&127) ; /*可将ch的奇偶校验位置成0*/ • /*06*/ }

  33. 【例9.5】位操作符经常用在加密程序中,可以在文件上做一些位操作,从而对原文件进行编码,生成一个不可读磁盘文件。最简单的方法是通过反码运算,将每个字节的每一位取反。设计一个函数encode ( )对字符进行编码。 • /*源程序名:CH0905.C*/ • /*01*/ char encode(ch) • /*02*/ { • /*03*/ char ch; • /*04*/ return (~ch);/*反码运算,对字符进行编码*/ • /*05*/ }

  34. 习题二 • 一、选择题 • 1. 在位运算中,操作数每左移一位,则结果相当于________。 • A.操作数乘以2 B.操作数除以2 • C.操作数除以4 D.操作数乘以4 • 2. 若有运算符<<,sizeof,^,&=,则它们按优先级由高至低的正确排列次序是________。 • A.sizeof,&=,<<,^ B.sizeof,<<,^,&= • C.^,<<,sizeof,&= D.<<,^,&=,sizeof • 3. 在c语言中,要求运算数必须是整型或字符型的运算符是________。 • A.&& B.& C.! D.||

  35. 4. 以下叙述中不正确的是________。 • A.表达式a&=b等价于a=a&b B.表达式a|=b等价于a=a|b • C.表达式a!=b等价于a=a!b D.表达式a^=b等价于a=a^b

  36. 二、填空题 • 1. 在c语言中,&运算符作为单目运算符时表示的是________运算;作为双目运算符时表示的是________运算 • 2. 与表达式 a&=b 等价的另一书写形式是________。 • 3. 与表达式x^=y-2等价的另一书写形式是________。 • 4. 若x=2,y=3,则x&y的结果是________。 • 5. 设a,b为整型量,且a=7,b=8,则表达式 a=a | b<<2 && ~b的值为________。 • 6. 设二进制数a是00101101,若想通过异或运算a^ b使a的高4位取反,低4位不变,则二进制数b应是________。

  37. 三、程序分析题(分析程序,写出运行结果) • 1. 下面程序段的运行结果是:________ • unsigned a=0356,b; • b=~a|a<<2+1; • printf(“%x\n”,b); • 2. 请读程序片段: • inta=1,b=2; • if(a&b)printf("***\n"); • elseprintf("$$$\n"); • 以上程序片段的输出结果是:________ • 3. • #include "stdio.h" • void main ( )

  38. { char x=040 ; printf ( “%d\n”, x=x << 1 ) ; • } • 4. • #include "stdio.h" • void main() • { • unsigned a,b,c,d; • printf("\ninput a octal number(a):"); • scanf(“%o”,&a); /* 输入一个8进制数据 */ • b=( a>>4); /* 将变量a右移4位 */

  39. c=~(~0<<4); /* 设置一个低4位全为1, 其余全为0的数 */ • d=b&c; • printf("a=%o\n%o\n",a,d); • } • 5. • #include "stdio.h" • void main() • { • int i; • unsigned int v; • v=~0; /* 将int 型单元各二进制位置为1 */

  40. for (i=1; (v=v>>1)>0; i++) ; /* 计算int 单元中的位数 */ • printf("\nThe length of INT is:%d", ( i )); • }

  41. 四、程序设计题 • 1. 取一个整数a从右端开始的4~7位。 • 2. 输出一个整数中由8~11位构成的数。 • 3. 从键盘上输入1个正整数给int变量num,按二进制位输出该数。

  42. C语言程序设计 主讲:沈济南 TEL:13971887071 E-mail:shenjinan@163.com

More Related