资源预览内容
第1页 / 共30页
第2页 / 共30页
第3页 / 共30页
第4页 / 共30页
第5页 / 共30页
第6页 / 共30页
第7页 / 共30页
第8页 / 共30页
第9页 / 共30页
第10页 / 共30页
亲,该文档总共30页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
C 语言编程开发中用好位操作符1. C 语言中的位操作符因为 C 语言的设计目的是取代汇编语言,所以它必须支持汇编语言所具有的运算能力,所以 C 语言支持全部的位操作符(Bitwise Operators)。位操作是对字节或字中的位(bit)进行测试、置位或移位处理,在对微处理器的编程中,特别适合对寄存器、I/O 端口进行操作。因而本节将对此作比较详细地介绍。6 种位操作符的形式与含义如下:& :按位“与”(AND);| :按位“或”(OR); :按位“异或”(XOR); : “取反” (NOT); :数据右移; 将变量的各位按要求向右移动若干位。右移语句的通常形式是:variable 右移位数如:a = 1111 0000;进行 a = a 2 操作后,a = 0011 1100。6) 数据左移数据左移操作符 将变量的各位按要求向左移动若干位。左移语句的通常形式是:variable 左移位数如:a = 1111 0000;进行 a = a 2 操作后,a =1100 0000。无论是左移还是右移,当某位从一端移出时,另一端出现的空白将以从外面移入的 0(某些计算机是送 1,详细内容请查阅相应 C 编译程序用户手册)来补充。这说明,移位不同于循环,从一端移出的位并不送回到另一端去,移去的位永远丢失了,同时在另一端只能补上相应位数的 0。移位操作可用于整数的快速乘除运算,左移一位等效于乘 2,而右移一位等效于除以 2。如:x = 7, 二进制表达为:0000 0111,x 10000 1110,相当于: x =2*7=14,x 30111 0000,相当于: x=14*2*2*2=112x 20011 0000,x=48x 30000 0110x=48/8=6x 10000 0011x=6/2=3移位操作还可以配合其它位操作夫对寄存器或者数据 I/O 接口的各个位进行设置、检测,具体方法见下一节。2.位操作符的一些实用方法介绍1) 学会应用复合运算符如前面所介绍的,位操作运算符可以和赋值运算符“=”一起组成复合运算符。即如下 5 个:=、&=、=、|=其中,x = y,相当于 x = x = y,相当于 x = x y;x & = y, 相当于 x = x & y;x = y, 相当于 x = x y;x | = y,相当于 x = x | y;学会在 C 语言中使用复合运算符,可以简化源程序,优化目标程序。2) C 语言中一些常见的位操作方法由于我们此处学习 C 语言的目的主要是为了开发微控制器的控制程序,为此我们特别关注一下对 MPU 的寄存器、I/O 中某一位的操作语句。假如要对 PORTA(端口 A)的某些位进行赋值、置 0、置 1、取反、测试,可能会用到如一下一些语句: PORTA= 0x87给整个 PORTA 赋值,作用是将 1000 0111 这个数赋予 PORTA,即让 PORTA 的第 0、1、2和 7 位置 1,其它位清 0。 PORTA= (17)给整个 PORTA 赋值,作用等价于 PORTA = 0x80,将 1000 0000 这个数赋予 PORTA,将指定的第 7 位置 1,其余各位置 0。只不过这里包括了两个步骤,即先是括号中的 17 操作,表示将 0x01 这个数左移 7 位,其值变成 0x80,再将它赋予 PORTA。 PORTA= (17) | (1 3) | (1 2)给整个 PORTA 赋值,作用与中的操作相同,但是是分别对 7、3、2 位置 1,而将其它各位均置 0。它先要分别对三个括号中给定的值进行移位操作,再将它们按位“与” ,最后将值赋予 PORTA。即:1000 0000(1 7)0000 1000(1 3)|0000 0100(1 2)PORTA=1000 1100 PORTA& = 0x80使 PORTA 中的指定位清 0,等价于 PORTA =PORTA & (0x80)。由于 0x80 的二进制表达形式为 1000 0000,利用其最高位为 1,其它各位均为 0 的特性,作为一个模板将其等于 1 的那些位(如本例中的第 7 位)屏蔽起来,使之保持不变,而将其它位清 0(不管原来为 0 还是为1)。因为 PORTA 与 0x80 按位“与”的结果如下:PORTA= 0x871000 0111&0x801000 0000=1000 0000操作后,第 7 位的原来值 1 被保留,其它各个位被清 0,其中最低的 3 位原来为 1,现在均为 0 了。 PORTA& = (17)它也等价于 PORTA & = 0x80:这里也包括了两个步骤,即先执行括号中的 17 操作,将0x01 左移 7 位,其值变成 0x80,再将它与 PORTA 做按位“与” 。该操作将除指定的第 7 位以外的各个位清 0。PORTA& = (1 7)该指令在等号后面加了取反符号 。与上一条操作的区别是,在与 PORTA 做按位“与”前,还将 0x80 先行取反,将 1000 0000 转换成 0111 1111,再做按位“与”操作。这样的操作结果是将指定的第 7 位清零,其它各位保持不变。 PORTA| = (17)等价于 PORTA= PORTA| (17),这里也是先执行括号中的 17 操作,将 0x01 左移 7 位,其值变成 0x80,再将它与 PORTA 做按位“或” 。若操作前 PORTA 的初始值为 0x07,则:PORTA0000 0111|0x801000 0000PORTA=1000 0111该操作将最高位置 1,其它各位保持不变。要注意的是,这条指令与 PORTA = (17) 相比,虽然都可以使指定的某一位置 1,但它们有着不同之处。PORTA = (17) 执行后,虽然某一位被置 1 了,但其它的位却被修改了,即不管 PORTA 的初始值为什么, 原来为 1 的位都会被 0 覆盖, 执行的结果总是为 1000 0000。而本条指令却可以将其它位屏蔽起来, 在改变要设置的那一位的同时, 并不改变其它位的状态。3) 巧用 C 语言中的位操作方法 将寄存器的指定位置 1 或清 0在实际应用中,经常利用:PORTA| = (1 n) 这条指令将寄存器的任意位置 1, 而又不影响其它位的现有状态。 比如说,你如果想将第 4 位置 1,就使用:PORTA| = (1 4) 就行了。当然,也可以使用:PORTA | = (1 7) | (1 4 ) | (1 0) 这样的指令一次将设第 8、5 和 1 位置 1,但又不影响到其它位的状态。在实际应用中,经常利用:PORTA & = (1 n) 这条指令将寄存器的任意位清 0,而又不影响其它位的现有状态。比如说,你如果想将第 4 位清 0,就使用:PORTA& = (1 4) 就行了。在启动 nRF905 芯片向空中发送数据时,采用以下函数:/* ShockBurst 发射数据 */void nrf905_TxSend(void)PORTD|=(110usPORTD &= (1TRXCE);其中让 PORTD 中控制 TRX_CE 信号的那一位先置 1,再清 0,输出一高一低的脉冲信号,就在一个脉冲周期内,完成了一次数据发送。因为在程序的开头已经定义 TRX_CE 信号为PD6 位,即 TRXCE = 6,因而上面两行程序等价于:PORTD|=(1 6);PORTD &= (1 6); 测试寄存器指定位的状态nRF905 在接收数据过程中,要分别发出 CD、AM 和 DR 信号,而 MPU 也要分别对这些位进行检测,看它们是否变高,若变高,就执行下一步,否则就跳出分支,返回主程序。下面就是对这些位进行检测的一段函数:/*检查接收情况*/void nrf905_RxRecv(void)while (PIND&(1CD)=0); /CD 引脚置 1,检测到载波信号while (PIND&(1AM)=0); /一般先 AM=1 指示地址匹配对while (PIND&(1DR)=0); /DR=1 时表示数据接收对而且 Crc 正确/nrf905 已经接收到数据nrf905_ReadData(0);/读出 nrf905 中的数据其中有:while(PIND&(1DR)= =0); 或者:if(PIND&(1DR)= =0); 语句,其功能就是对寄存器指定的位进行测试。括号中是一个等式,我们将其拆分开介绍它的作用:1DR:DR 在程序的开始已经被定义为 2,(1DR)也就是(1 2),表示将 0x01 左移 2 位,结果为0000 0100;PIND& (1DR):PIND 为 PORTD 端口的 8 位引脚的值,PIND& (1DR)表示让它和(1DR) 亦即和 00000100 按位相“与” 。不管 PIND 的其它位为何值,由于和 0 相与,这些位的结果都为 0,我们关心的只有第 2 位的状态。由于该位与 1 相与,只要 DR 为高,就会有:PINDxxx x1xx&0000 0100结果=0000 0100结果的第二位的状态为 1,也就是整个表达式:(PIND&(1DR)= = 0 不成立,语句的逻辑值为 0。若 DR 为低,则有:PINDxxxx x0xx&0000 0100结果=0000 0000也就是整个表达式的结果为 0,(PIND&(1DR)= = 0 成立,语句的逻辑值为 1。根据括号中逻辑值的情况,while 或者 if 语句再决定程序的流向。单片机的C语言中位操作用法单片机的C语言中位操作用法默认分类2009-07-25 22:07阅读62评论1字号: 大大中中小小在对单处机进行编程的过程中,对位的操作是经常遇到的。C51对位的操控能力是非常强大的。从这一点上,可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点。这也是在各个领域中都可以看到C的重原因。在这一节中将详细讲解C51中的位操作及其应用。1、位运算符C51提供了几种位操作符,如下表所示:1)“按位与”运算符(&)参加运算的两个数据,按二进位进行“与”运算。原则是全1为1,有0为0,即:0&0=0; 0&1=0; 1&0=0; 1&1=1;如下例:a=5&3; /a=(0b 0101) & (0b 0011) =0b 0001 =1那么如果参加运算的两个数为负数,又该如何算呢?会以其补码形式表示的二进制数来与运算。a=-5&-3; /a=(0b 1011) & (0b1101) =0b 1001 =-7在实际的应用中与操作经常被用于实现特定的功能:1.清零“按位与”通常被用来使变量中的某一位清零。如下例:a=0xfe; /a=0b 11111110a=a&0x55;/使变量a的第1位、第3位、第5位、第7位清零 a= 0b 010101002.检测位要知道一个变量中某一位是1还是0,可以使用与操作来实现。a=0xf5; /a=0b 11110101result=a&0x08; /检测a的第三位,result=03.保留变量的某一位要屏蔽某一个变量的其它位,而保留某些位,也可以使用与操作来实现。a=0x55; /a=0b 01010101运算符含义运算符含义&按位与取反|按位或右移a=a&0x0f; /将高四位清零,而保留低四位 a=0x052)“按位或”运算符()参与或操作的两个位,只要有一个为1,则结果为1。即有1为10为0。0|0=0; 0|1=1; 1|0=1; 1|1=1;例如:a=0x30|0x0f; /a=(0b00110000)|(0b00001111)=(0b00111111)=0x3f“按位或”运算最普遍的应用就是对一个变量的某些位置1。如下例:a=0x00; /a=0b 00000000a=a|0x7f; /将a的低7位置为1,a=0x7f3)“异或”运算符()异或运算符又被称为XOR运算符。当参与运算的两个位相同(1与1或与0)时结果为0。不同时为1。即相同为0,不同为1。00=0; 01=1; 10=1;11=0;例如:a=0x550x3f; /a=(0b01010101)(0b00111111)=(0b01101010)=0x6a异或运算主要有以下几种应用:1.翻转某一位当一个位与1作异或运算时结果就为此位翻转后的值。如下例:当一个位与1作异或运算时结果就为此位翻转后的值。如下例:a=0x35; /a=0b00110101a=a0x0f; /a=0b00111010 a的低四位翻转关于异或的这一作用,有一个典型的应用,即取浮点的相反数,具体的实现下:f=1.23; /f为浮点型变量值为1.23f=f*-1; /f乘以-1,实现取其相反数,要进行一次乘运算f=1.23;(unsigned char *)&f)0=0x80; /将浮点数f的符号位进行翻转实现取相反数2.保留原值当一个位与0作异或运算时,结果就为此位的值。如下例:a=0xff; /a=0b11111111a=a0x0f; /a=0b11110000 与0x0f作异或,高四位不变,低四位翻转3.交换两个变量的值,而不用临时变量要交换两个变量的值,传统的方法都需要一个临时变量。实现如下:void swap(unsigned char *pa,unsigned char *pb)unsigned char temp=*pa;/定义临时变量,将pa指向的变量值赋给它*pa=*pb;第 1 页单片机的C语言中位操作用法*pb=temp;/变量值对调而使用异或的方法来实现,就可以不用临时变量,如下:void swap_xor(unsigned char *pa,unsigned char *pb)*pa=*pa*pb;*pb=*pa*pb;*pa=*pa*pb; /采用异或实现变量对调从上例中可以看到异或运算在开发中是非常实用和神奇的。4)“取反”运算符()与其它运算符不同,“取反”运算符为单目运算符,即它的操作数只有一个它的功能就是对操作数按位取反。也就是是1得0,是0得1。1=0; 0=1;如下例:a=0xff; /a=0b11111111a=a; /a=0b000000001.对小于0的有符号整型变量取相反数d=-1;/d为有符号整型变量,赋值为-1,内存表示为0b 11111111 11111111d=d+1; /取d的相反数,d=1,内存表示0b 00000000 00000001此例运用了负整型数在内存以补码方式来存储的这一原理来实现的。负数的补码方式是这样的:负数的绝对值的内存表示取反加1,就为此负数的内存表示。如-23如果为八位有符号整型数,则其绝对值23的内存表示为0b00010111,对其取反则为0b11101000再加1为0b11101001,即为0XE9,与Keil仿真结果是相吻合的:2.增强可移植性关于“增强可移植性”用以下实例来讲解:假如在一种单片机中unsigned char类型是八个位(1个字节),那么一个此型的变量a=0x67,对其最低位清零。则可以用以下方法:a=0x67; /a=0b 0110 0111a=a&0xfe; /a=0b 0110 0110上面的程序似乎没有什么问题,使用0xfe这一因子就可以实现一个unsigned char型的变量最低位清零。但如果在另一种单片机中的unsigned char类型被定义为16个位(两个字节),那么这种方法就会出错,如下:b=0x6767; /假设b为另一种单片机中的unsigned char 类型变量,值为0b 01100111 0110 0111b=b&0xfe; /如果此时因子仍为0xfe的话,则结果就为0b 0000 0000 0110 01100x0066,而与0x6766不相吻合上例中的问题就是因为不同环境中的数据类型差异所造成的,即程序的可移植性不好。对于这种况可以采用如下方法来解决:a=0x67; /a=0b 0110 0111a=a&1; /在不同的环境中1将自动匹配运算因子,实现最后一位清零a=0x66其中1为 0b 11111110b=0x6767; /a=0b 0110 0111 0110 0111b=a&1; /1=0b 1111 1111 1111 1110,b=0b 0110 0111 0110 0110 ,即0x67665)左移运算符()左移运算符用来将一个数的各位全部向左移若干位。如:a=a2表示将a的各位左移2位,右边补0。如果a=34(0x22或0b00100010),左移2位得0b10001000,即十的136。高位在左移后溢出,不起作用。从上例可以看到,a被左移2位后,由34变为了136,是原来的4倍。而如果左移1位,就为0b01000100,即十进制的68,是原来的2倍,很显然,左移N位,就等乘以了2N。但一结论只适用于左移时被溢出的高位中不包含1的情况。比如a=64; /a=0b 0100 0000a=a1表示将a的各位向右移动1位。与左移相对应的,左移一位就相当于除以2,右移N位,就相当于除以2N。在右移的过程中,要注意的一个地方就是符号位问题。对于无符号数右移时边高位移和0。对于有符号数来说,如果原来符号位为0,则左边高位为入0,而如果符号位为1,则左边移入0还是1就要看实际的编译了,移入0的称为“逻辑右移”,移入1的称为“算术右移”。Keil中采用“算术右移”的方式来进行编译。如下:d=-32; /d为有符号整型变量,值为-32,内存表示为0b 11100000第 2 页单片机的C语言中位操作用法d=d1;/右移一位 d为 0b 11110000 即-16,Keil采用算术逻辑进行编译7)位运算赋值运算符在对一个变量进行了位操作中,要将其结果再赋给该变量,就可以使用位算赋值运算符。位运算赋值运算符如下:&=, |=,=,=,=例如:a&=b相当于a=a&b,a=2相当于a=2。8)不同长度的数据进行位运算如果参与运算的两个数据的长度不同时,如a为char型,b为int型,则编译将二者按右端补齐。如果a为正数,则会在左边补满0。若a为负数,左边补满1。如果a为无符号整型,则左边会添满0。a=0x00; /a=0b 00000000d=0xffff; /d=0b 11111111 11111111d&=a; /a为无符号型,左边添0,补齐为0b 00000000 00000000,d=0b 0000000000000000第 3 页单片机的 C 语言中位操作用法在对单处机进行编程的过程中,对位的操作是经常遇到的。C51 对位的操控能力是非常强大的。从这一点上,就可以看出 C 不光具有高级语言的灵活性,又有低级语言贴近硬件的特点。这也是在各个领域中都可以看到 C 的重要原因。在这一节中将详细讲解 C51 中的位操作及其应用。1、位运算符C51 提供了几种位操作符,如下表所示:运算符含义运算符含义&按位与取反|按位或右移1)“按位与”运算符(&)参加运算的两个数据,按二进位进行“与”运算。原则是全 1 为 1,有 0 为 0,即:0&0=0; 0&1=0; 1&0=0; 1&1=1;如下例:a=5&3; /a=(0b 0101) & (0b 0011) =0b 0001 =1那么如果参加运算的两个数为负数,又该如何算呢?会以其补码形式表示的二进制数来进行与运算。a=- 5&- 3; /a=(0b 1011) & (0b1101) =0b 1001 =- 7在实际的应用中与操作经常被用于实现特定的功能:1.清零“按位与”通常被用来使变量中的某一位清零。如下例:a=0xfe; /a=0b 11111110a=a&0x55;/使变量使变量 a 的第的第 2 位位、 第第 4 位位、 第第 6 位位、 第第 8 位清零位清零 a= 0b010101002.检测位要知道一个变量中某一位是1还是0,可以使用与操作来实现。a=0xf5; /a=0b 11110101result=a&0x08; /检测检测 a 的第的第 4 位位,result=03.保留变量的某一位要屏蔽某一个变量的其它位,而保留某些位,也可以使用与操作来实现。a=0x55; /a=0b 01010101a=a&0x0f; /将高四位清零将高四位清零,而保留低而保留低四位四位 a=0x052)“按位或”运算符()参与或操作的两个位,只要有一个为1,则结果为1。即有1为1,全0为0。0|0=0; 0|1=1; 1|0=1; 1|1=1;例如:a=0x30|0x0f;/a=(0b00110000)|(0b00001111)=(0b00111111)=0x3f“按位或”运算最普遍的应用就是对一个变量的某些位置1。如下例:a=0x00; /a=0b 00000000a=a|0x7f; /将将 a 的低的低 7 位置为位置为 1,a=0x7f3)“异或”运算符()异或运算符又被称为 XOR 运算符。当参与运算的两个位相同(1与1或0与0)时结果为0。不同时为1。即相同为 0,不同为 1。00=0; 01=1; 10=1;11=0;例如:a=0x550x3f;/a=(0b01010101)(0b00111111)=(0b01101010)=0x6a异或运算主要有以下几种应用:1.翻转某一位当一个位与1作异或运算时结果就为此位翻转后的值。如下例:a=0x35; /a=0b00110101a=a0x0f; /a=0b00111010 a 的低四位翻转的低四位翻转关于异或的这一作用,有一个典型的应用,即取浮点的相反数,具体的实现如下:f=1.23; /f 为浮点型变量为浮点型变量值为值为 1.23f=f*- 1; /f 乘以乘以- 1,实现取其相反数实现取其相反数,要进行一次乘运算要进行一次乘运算f=1.23;(unsigned char *)&f)0=0x80; /将浮点数将浮点数 f 的符号位进的符号位进行翻转实现取相反数行翻转实现取相反数2.保留原值当一个位与0作异或运算时,结果就为此位的值。如下例:a=0xff; /a=0b11111111a=a0x0f; /a=0b11110000 与与 0x0f 作异或作异或,高四位不变高四位不变,低四位翻转低四位翻转3.交换两个变量的值,而不用临时变量要交换两个变量的值,传统的方法都需要一个临时变量。实现如下:void swap(unsigned char *pa,unsigned char *pb)unsigned char temp=*pa;/定义临时变量定义临时变量,将将 pa 指向的变指向的变量值赋给它量值赋给它*pa=*pb;*pb=temp;/变量值对调变量值对调而使用异或的方法来实现,就可以不用临时变量,如下:void swap_xor(unsigned char *pa,unsigned char *pb)*pa=*pa*pb;*pb=*pa*pb;*pa=*pa*pb; /采用异或实现变量对调采用异或实现变量对调从上例中可以看到异或运算在开发中是非常实用和神奇的。4)“取反”运算符()与其它运算符不同,“取反”运算符为单目运算符,即它的操作数只有一个。它的功能就是对操作数按位取反。也就是是1得0,是0得1。1=0; 0=1;如下例:a=0xff; /a=0b11111111a=a; /a=0b000000001.对小于 0 的有符号整型变量取相反数d=- 1;/d 为有符号整型变量为有符号整型变量,赋值为赋值为- 1,内存表示为内存表示为 0b11111111 11111111d=d+1; /取取 d 的相反数的相反数,d=1,内存表示内存表示 0b 0000000000000001此例运用了负整型数在内存以补码方式来存储的这一原理来实现的。 负数的补码方式是这样的:负数的绝对值的内存表示取反加1,就为此负数的内存表示。如- 23 如果为八位有符号整型数, 则其绝对值 23 的内存表示为 0b00010111, 对其取反则为 0b11101000, 再加 1 为 0b11101001, 即为 0XE9, 与 Keil仿真结果是相吻合的:2.增强可移植性关于“增强可移植性”用以下实例来讲解:假如在一种单片机中 unsigned char 类型是八个位(1个字节),那么一个此类型的变量 a=0x67,对其最低位清零。则可以用以下方法:a=0x67; /a=0b 0110 0111a=a&0xfe; /a=0b 0110 0110上面的程序似乎没有什么问题, 使用 0xfe 这一因子就可以实现一个 unsignedchar 型的变量最低位清零。但如果在另一种单片机中的unsigned char 类型被定义为 16 个位(两个字节),那么这种方法就会出错,如下:b=0x6767; /假设假设b为另一种单片机中的为另一种单片机中的unsigned char 类类型变量型变量,值为值为 0b 0110 0111 0110 0111b=b&0xfe; /如果此时因子仍为如果此时因子仍为 0xfe 的话的话,则结果就为则结果就为 0b0000 0000 0110 0110 即即 0x0066,而与而与 0x6766不相吻合不相吻合上例中的问题就是因为不同环境中的数据类型差异所造成的, 即程序的可移植性不好。对于这种情况可以采用如下方法来解决:a=0x67; /a=0b 0110 0111a=a&1; /在不同的环境中在不同的环境中1 将自动匹配运算因子将自动匹配运算因子,实现实现最后一位清零最后一位清零a=0x66 其中其中1 为为 0b11111110b=0x6767; /a=0b 0110 0111 0110 0111b=a&1; /1=0b 1111 1111 1111 1110,b=0b 0110 01110110 0110 ,即即 0x67665)左移运算符()左移运算符用来将一个数的各位全部向左移若干位。如:a=a2表示将 a 的各位左移 2 位,右边补 0。如果 a=34(0x22 或 0b00100010),左移2 位得 0b10001000,即十进制的 136。高位在左移后溢出,不起作用。从上例可以看到, a 被左移 2 位后, 由 34 变为了 136,是原来的 4 倍。而如果左移 1 位,就为 0b01000100,即十进制的 68,是原来的 2 倍,很显然,左移 N 位,就等于乘以了 2N。但一结论只适用于左移时被溢出的高位中不包含1的情况。比如:a=64; /a=0b 0100 0000a=a1表示将 a 的各位向右移动 1 位。 与左移相对应的,左移一位就相当于除以 2,右移 N 位,就相当于除以 2N。在右移的过程中, 要注意的一个地方就是符号位问题。对于无符号数右移时左边高位移和0。对于有符号数来说,如果原来符号位为0,则左边高位为移入0,而如果符号位为1,则左边移入0还是1就要看实际的编译器了,移入0的称为“逻辑右移”,移入1的称为“算术右移”。Keil 中采用“算术右移”的方式来进行编译。如下:d=- 32; /d 为有符号整型变量为有符号整型变量,值为值为- 32,内存表示为内存表示为 0b11100000d=d1;/右移一位右移一位 d 为为 0b 11110000 即即- 16,Keil 采用采用算术逻辑算术逻辑进行编译进行编译7)位运算赋值运算符在对一个变量进行了位操作中, 要将其结果再赋给该变量,就可以使用位运算赋值运算符。位运算赋值运算符如下:&=, |=,=,=,=例如:a&=b 相当于 a=a&b,a=2 相当于 a=2。8)不同长度的数据进行位运算如果参与运算的两个数据的长度不同时,如 a 为 char型,b 为 int 型,则编译器会将二者按右端补齐。如果 a 为正数, 则会在左边补满 0 。 若 a 为负数, 左边补满 1 。如果 a 为无符号整型,则左边会添满0。a=0x00; /a=0b 00000000d=0xffff; /d=0b 11111111 11111111d&=a; /a 为无符号为无符号型型,左边添左边添 0,补齐为补齐为 0b 0000000000000000,d=0b 00000000 00000000 位操作与文件操作 192 位操作与文件操作 一、 位运算的含义及使用 计算机真正可执行的是由 0 和 1 信号所组成的机器指令,数据也以二进制表示。最终要实现计算机的操作, 就要对这些 0 和 1 信号进行操作。 每一个 0 和 1 的状态称为一个 “位(bit)的状态。 C 语言具有直接操作字节或位的能力, 这只是对 C 中的 int 和 char 类型的数据,这种操作称为位操作或位运算。机器指令和汇编语言能够直接进行位操作。 二、 位运算符 1位运算符如 C 语言的位运算符有:位反、位与、位或、位异或、右移位、左移位及由位运算符和赋值运算符构成的复合的赋值运算符,见表 10-1 所示。 2位运算符的含义及优先级 考点与重难点解析 备必知识考点精要重点难点 1 1 1 1 大纲要求 位操作: 1位运算符的含义及使用。 2简单的位运算。 文件操作: 只要求缓冲文件系统(即高级磁盘 I/O 系统),对非标准缓冲文件系统(即低级磁盘 I/O 系统)不要求。 1文件类型指针(FILE 类型指针)。 2文件的打开与关闭(fopen,fclose)。 3文件的读写(fputc,fgetc,fputs,fgets,fread,fwrite,fprintf,fscanf函数), 文件的定位(rewind,fseek 函数)。 第 10 章 位操作与文件操作 193位预算符的优先级的顺序由高到低为: (按位取反): 它是位运算符中唯一的单目运算符,置于运算对象的左边。其运算功能是把运算对象的内容按位取反,即把变为 0 或 0 变为 1。作运算时,一般先将运算对象转化为二进制。 例如把6 转化为二进制为(00000110)(11111001),再转化为十进制等于 249。 (左移): 它是双目运算符,运算符左边是移位对象,右边是整型表达式,代表左移的位数。移位时,右端补 0,左端移出的部分舍弃。运算时也一般要先将移位对象转化为二进制表示,然后再行移位。例如有定义 a=6,转化为二进制 a=00000110,则 a = 3 C (右移):它的使用方法和左移相同,只是移位的方向不同。右移时,右端移出的部分舍弃,左端的移入分两种情况:对于无符号整数和正整数,高位补 0;对于负整数,高位补 1。 & (按位与):对应位同时为时结果为,否则为。 (按位异或):对应位不相同时结果为,相同时结果为。 | (按位或):对应位只要有一个为结果即为,都为时结果为 =、=、&=、=、|=(位赋值运算) :位操作赋值运算的过程是,两个操作数进行位操作,然后将结果赋予第一个操作数。所以第一个操作数必须是变量。位操作赋值运算与算术赋值运算相似,统称复合赋值运算 三、 文件类型指针(FILE 类型指针) C 语言中的文件分缓冲型文件和非缓冲型文件两种, 此处只讨论缓冲型文件。 对于缓冲型文件, 每个被使用的文件都在内存中开辟一个区, 用来存放文件的有关信息(如文件名字、文件状态及文件当前位置等)。这些信息保存在有关结构体类型的变量中。该结构体类型由系统定义,取名为 FILE,也叫文件类型指针。 四、 文件的打开与关闭(fopen,fclose) 1C 语言对某个文件读写之前应该打开该文件,在使用结束之后应关闭该文件。 位操作与文件操作 1942C 语言中打开文件用 fopen()函数,fopen()函数的调用方式通常为: FILE *fp; fpfopen (文件名,使用文件方式); 文件用 fopen()函数打开时,应根据文件的使用方式来选择文件使用方式的特殊符号。以“r”方式打开的文件,只能从文件向内存读入数据,而不能从内存向该文件写数据。并且“r”方式只能打开一个已存在的文件。 以 “w” 方式打开的文件, 只能从内存向该文件写数据, 而不能从文件向内存输入数据。如果该文件原来不存在,则打开时建立一个以指定文件名命名的文件。如果原来的文件已经存在,则打开时将文件的内容删掉,然后重新建立一个新文件。以“a”方式打开的文件,是向一个已经存在的文件的尾部添加新数据(保留原文件中已有的数据)。打开文件时,文件的位置指针在文件的末尾。 3对打开的文件使用完后用 fclose 函数关闭文件,fclose 函数调用的一般形式为: felose ( 文件指针 ); 改命令将通知系统,将此指针指向的文件关闭,也就是释放文件信息区。如不关闭文件而直接使程序停止运行,就会丢失缓冲区中还未写入文件的信息,而且影响操作系统的打开文件的总数限制,因此注意文件用完后必须关闭。 五、 文件的读写 文件打开以后, 就可以对它进行读写操作了, 对文件的读写可以用 fputc、 fgetc、 fputs、fgets、fread、fwrite、fprintf、fscanf 函数,文件的定位可以用 rewind、fseek 函数。 1fputc 函数和 fgete 函数 fputc 函数把一个字符写到磁盘文件去,其一般形式为: fputc (ch,fp); 其中 ch 是要输出的字符,它可以是一个字符常量,也可以是一个字符变量,fp 是文件指针它从 fopen 函数得到返回值。 fgetc 函数从指定的文件读入一个字符,该文件必须是以读或写方式打开的,其一般调用形式为: ch=fgete(fp); fp 为文件型指针变量,ch 为字符变量。fgete 函数带回一个字符,赋给 ch。 2fread 函数和 fwrite 函数 fread 函数可以用来一次读一组数据。fwrite 函数可以用来一次向文件中写一组数据。它们的调用形式为: fread(buffer,size,count,fp) fwrite(buffer,size,count,fp) 其中:buffer 是一个指针。size 为要读写的字节数。count 为要进行读写多少个 siae字节的数据项。fp 为文件型指针。 3fprintf 函数和 fscanf 函数 fprinff 函数、fscanf 函数与 printf 函数、scanf 函数作用相似,都是格式化读写函数。只第 10 章 位操作与文件操作 195有一点不同: fprintf 函数和 fscanf 函数的读写对象不是终端而是磁盘文件。 一般调用形式为: fpfind(文件指针,格式字符串,输出列表); fscanf(文件指针,格式字符串,输出列表); 4fgets 函数和 fputs 函数 fgets 读出一入字符串,fputs 函数输出一个字符串,它们的形式为: fgets(str,n,fp); fputs(str,fp) ; fgets 函数从 fp 指向的文件读取 n-1 个字符, 并将它放到字符数组 str 中, 直到遇到 “n”或文件结束符 EOF 即结束读入。 单将遇到的换行符 “n” 也作为一个祖父送入到 str 数组中,在读入的字符之后自动加入一个“0” ,因此 str 数组中的字符串最多可占用 n 个字节。fgets函数返回值为 str 数组首地址。如读到文件尾或读错返回 NULL。 fputs 函数将字符数组 str 中的字符串(或字符指针指向的串,或字符串常量)输出到 fp所指向的文件,但字符串结束符“0”不输出。 5rewind 函数和 fseek 函数 文件中有一个位置指针,指向当前的读写位置。如果顺序读写一个文件,每次读写一个字符,则读写完一个字符后,该位置指针自动移动指向下一个字符位置。如果想改变这样的规律,强制使位置指针指向其他指定的位置,可以用调用形式 rewind 和 fseek 函数。 rewind 函数的作用是使位置指针重新返回文件的开头,此函数没有返回值。 fseek 函数可以改变文件的位置指针。fseek 函数的调用形式为: fseek(文件类型指针,位移量,起始点); “起始点”用 0、1 或 2 代替,0 代表文件开始,1 为当前位置,2 为文件末尾。 “位移量”是指以“起始点”为基点,向前移动的字节数。 【例题 1】 以下程序的输出结果是( ) 。 (2002.04) main() char x=040; printf(%on,x1); A100 B80 C64 D32 解析 注意本题是按 8 进制数给 x 赋值,将其转换成二进制为:00100000,在将其向左移 1 位得 01000000,然后仍然以 8 进制形式输出,所以最后结果应选择 A。 答案 A 【例题 2】以下程序的输出结果是( ) 。 (2001.04) A0 B1 C2 D3 main() int x=0.5; char z=a; 典型试题精解 经典例题相关知识解题分析 2 2 2 2 位操作与文件操作 196printf(%dn, (x&1)&(zz) ); 解析 执行 int x=0.5;语句后,x 的值为 0;所以(x&1)的值为 0;由此即可断定(x&1)&(zz)的值为 0。本题应选择 A。 答案 A 【例题 3】整型变量 x 和 y 的值相等、且为非 0 值,则以下选项中,结果为零的表达式是( ) 。 (2001.09) Ax | y Bx|y Cx & y D) x y 解析 |是逻辑或运算,A 选项的表达式的值为 1; & (按位与),其运算规则是:对应位同时为时结果为,否则为,由于 x 和 y 的值是相等的,所以表达式 x&y 的值不为 0; (按位异或),其运算规则是:对应位不相同时结果为,相同时结果为,由于 x和 y 的值是相等的,所以表达式 xy 的值为 0;| (按位或),其运算规则是:对应位只要有一个为结果即为,都为时结果为,所以 x|y 的值肯定不为 0。本题应选择 D。 答案 D 【例题 4】设有定义 char a,b;若想通过 a&b 运算保留 a 的第三位和第六位的值,则 b 的二进制数应是( ) 。 A00100100 B11100100 C00011011 D10101010 解析 由“与”运算的功能可知:两个对应的二进制数只要有为 0, “与”的结果就为 0,只要它们均为 1 时结果才为 1。因此,若想保留哪位上的数,就用 1 去“与” ,其他位用 0屏蔽掉。对于本题,我们可以取 b=00100100,假如 a=11110110,则 a&b 计算如下: a: 11110110 b: 00100100 a&b 00100100 “与”的结果保留了 a 的第三位 1 和第六位 1 的状态,其余位全为 0。 答案 A 【例题 5】 若要打开 A 盘上 user 子目录下名为 abc.txt 的文本文件进行读、写操作,下面符合此要求的函数调用是( ) 。 (2002.04) A fopen(A:userabc.txt,r) B fopen(A:userabc.txt,r+) C fopen(A:userabc.txt,rb) D fopen(A:userabc.txt,w) 解析 要进行读写操作,文件必须以读/写的方式打开,4 个选项中只有“r+”方式是读/写方式打开文件,r是只读方式打开一个字符文件,rb是只读方式打开一个二进制文件,w是只写方式打开一个字符文件。所以本题应选择 B。 答案 B 【例题 6】 下面的程序执行后,文件 test.txt 中的内容是( ) 。 (2001.09) #include void fun(char *fname,char *st) FILE *myf; int i; myf=fopen(fname,w ); 第 10 章 位操作与文件操作 197for(i=0;istrlen(st); i+) fputc(sti,myf); fclose(myf); main() fun(test,new world); fun(test,hello,); Ahello, Bnew worldhello, Cnew world D hello, rld 解析 本题是只写的方式打开文件,写的内容应该是最后一次调用函数写入的内容,因为打开的是同一个文件,后一次打开要写入字符后。前一次打开写入的字符就被改写了,因为不是以添加方式a打开的。所以本题应选择。 答案 【例题 7】 若 fp 是指向某文件的指针,且已读到文件末尾,则库函数 feof(fp)的返回值是( ) 。 (2001.04)AEOF B1 C非零值 DNULL 解析 本题是考查函数的返回的值,feof(fp)函数在遇到文件结束符时返回非零值,否则返回。所以本题应选择。 答案 【例题 8】C 语言中系统的标准输入文件是指( )。 A键盘 B显示器 C软盘 D硬盘 解析 此题考查有关标准设备的知识。在多数 C 语言版本中,stdio.h 文件至少定义了四种标准设备文件指针,可以直接引用而不必含有打开操作,它们是: 标准输入文件指针 stdin 缺省为键盘; 标准输出文件指针 stdout 缺省为显示器; 标准错误输出文件指针 stderr 缺省为显示器; 标准打印输出文件指针 stdprn 指打印机; 此外, 还可能包括如辅助设备等标准文件指针, 且多数文件指针可以被重新定向到其他设备。所以本题应选择 A。 答案 A 【例题 9】C 语言可以处理的文件类型是( )。 A文本文件和数据文件 B文本文件和二进制文件 C数据文件和二进制文件 D数据代码文件 解析 从文件的组织形式的角度看, C 语言有文本文件(ASCII 码文件)和二进制文件两种。文本文件的每一个字符占一个字节,存放其 ASCII 码值,可以在 DOS 系统下直接阅读,而二进制文件是内存数据的直接映像,是不可读的。所以本题应选择。 答案 位操作与文件操作 198【例题 10】 如果需要打开一个已经存在的非空文件”FILE”进行修改,正确的打开语句是( ) 。 Afp=fopen(“FILE” , “r”); Bfp=fopen(“FILE” , “ab+”); Cfp=fopen(”FILE” , “w+”); Dfp=fopen(”FILE” , “r+”); 解析 此题考查文件打开方式对文件操作的影响。由于打开文件进行修改,可见选项A 是错误的,因为此种方式打开时,只能读,不能写。选项 B 是以追加方式“ab+”打开文件读写,以这种方式打开时,新写入的数据只能追加在文件原有内容之后,但可以对以前的数据读出。换言之, “ab+”吼“a+”方式打开文件后,对于写操作,文件指针只能定位在文件的原有内容之后,但对于读操作,文件指针可以定位在全文件范围内,所以,按此种方式打开文件不能实现文件内容的修改。选项 C 以“w+”方式打开文件,此时,原文件中已存在的内容都被清除。但新写入文件的数据可以被再次读出或再次写入,故也不能实现对文件的修改。只有以“r+”方式打开文件时,才允许将文件原来数据读出,也允许在某些位置上再写入,从而实现对文件的修改。所以本题应选择 D。 答案 D 一、选择题 1下述程序中, ( )可以实现选项本身的功能要求. A)将一个整数 x 右移 m 位. B)计算一个整数 x 的高字节值. #include #include void main() void main() int x,m; int x; scanf(%d,%d,&x,&m); scanf(%d,&x); xm; x=x&0xff00; printf(%x,x); printf(%d,x); C)将整数 x 的高 4 位移入变量 y 的低 4 位. D)计算一个整数 x 的低字节的高 4 位值. #include #include void main() void main() int x=0xabcd,y; int x,y; y=x16-4; scanf(%d,&x); printf(%x,y); y=(x4)&0x000f; printf(%x,y); 2设 int b=2; 表达式(b2)/(b1)的值是( ) 。 A) 0 B) 2 C) 4 D) 8 3若有以下程序 考 前 必 练 强化训练考前自测参考答案 3 3 3 3 第 10 章 位操作与文件操作 199int a=3,b=4; a=ab; b=ba; a=ab; 则执行以上语句后 a 和 b 的值分别为( ) 。 A)a=3,b=4 B)a=4,b=3 C)a=4,b=4 D)a=3,b=3 4下面程序的输出结果是( ) 。 main() unsigned int a=3,b=10; printf(“%dn”,a1); A)1 B)5 C)12 D)13 5表达式 ab|c&d 的运算顺序是( ) 。 A) , &, , | B) , |, &, C) , &, |, D) , , &, | 6表达式 0x13&0x17 的值是( ) 。 A)0x17 B)0x13 C)0xf8 D)0xec 7在位运算中,操作数每右移一位,其结果相当于( ) 。 A)操作数乘以 2 B)操作数除以 2 C)操作数除以 4 D)操作数乘以 4 8在位运算中,操作数每左移一位,其结果相当于( ) 。 A)操作数乘以 2 B) 操作数除以 2 C)操作数除以 4 D) 操作数乘以 4 9请读程序片段: unsigned t=129; t=t00; printf(“%d,%on”,t,t); 以上程序片段的输出结果是( ) 。 A)0,0 B)129,201 C)126,176 D)101,145 10若 a=1,b=2 ,则 a | b 的值是( ) 。 A)0 B)1 C)2 D)3 11表达式0x13 的值是( ) 。 A)0xFFEC B)0Xff71 C)0Xff68 D)0xFF17 12下面程序的输出结果是( ) 。 main() char x=040; 位操作与文件操作 200 printf(%dn,x=x1); A) 10 B) 160 C) 120 D) 64 13执行下面的程序段后,B 的值为( ) 。 int x=35; char z=A;int B;B=(x&15)&(za); A) 0 B)1 C)2 D)3 14若 fp 是指向某文件的指针,且已读到此文件末尾,则库函数 feof(fp)的返回值是( ) 。 (2000.09) A) EOF B) 0 C) 非零值 D)NULL 15下述关于 C 语言文件操作的结论中, ( )是正确的。 A)对文件操作必须是先关闭文件 B)对文件操作必须是先打开文件 C)对文件操作顺序无要求 D)对文件操作前必须先测试文件是否存在,然后再打开文件 16已知函数 fread 的调用形式为 fread(buffer,size,count,fp),其中 buffer 代表的是( ) 。 A)存放读人数据项的存储区 B)一个指向所读文件的文件指针 C)存放读人数据的地址或指向此地址的指针 D)一个整型变量,代表要读入的数据项总数 17函数调用语句 fseek(fp,-10L,2);的含义是( ) 。 A)将文件位置指针移动距离文件头 10 个字节处 B)将文件位置指针从当前位置向文件尾方向移动 10 个字节 C)将文件位置指针从当前位置向文件头方向移动 10 个字节 D)将文件位置指针从文件未尾处向文件头方向移动 10 个字节 18C 语言可以处理的文件类型是( ) 。 A)文本文件和数据文件 B)本文件和二进制文件 C)数据文件和二进制文件 D)以上答案都不完全 19 以下程序将一个名为 f1.dat 的文件拷贝到一个名为 f2.dat 的文件中。 请选择正确的答案( (1) )和( (2) ) 填人对应的位置 #include main() char c; FILE *fpl,*fp2; fpl=fopen(“f1.dat”, (1) ); fp2=fopen(“f2.dat”,(2) ); c=fgetc(fpl); while(c!=EOF) fputc(c,fp2); c=fgetc(fpl); fclose(fpl); fclose(fp2); 第 10 章 位操作与文件操作 201return; (1) A”a” B”rb C”rb+” D”r” (2 )A”wb” B”wb+” C”w” D”ab” 20下列程序执行后的输出结果是( ) 。 A) -32767 B) FFFE C) -1 D) 32768 main() char x=0xFFFF; printf(%d n,x-); 二、填空题 1下面程序的运行结果是 ( 【1】 ) 。 mian() unsigned a=0112,x,y,z; x=a3; printf(“x=%o,”,x); y=(04); printf(“y=%o,”,y); z= x&y; printf(“z=%on”,z); 2设有 char a, b; 若要通过 a&b 运算屏蔽掉 a 中的其它位,只保留第 2 和第 8 位(右起为第 1 位) , 则 b 的二进制数是( 【2】 ) 。 3以下程序的运行结果是 ( 【3】 ) 。 main() char a=0x95,b,c; b=(a&0xf)4; a=b|c; printf(“%xn”,a); 4设 x=10100011,若要通过 xy 使 x 的高 4 位取反,低 4 位不变,则 y 的二进制数是 ( 【4】 ) 。 5与表达式 a&=b 等价的另一书写形式是 ( 【5】 ) 。 6与表达式 x=y-2 等价的另一书写形式是 ( 【6】 ) 。 7程序的输出结果是 ( 【7】 ) 。 main() unsigned a,b; a=0x9a; b=a; printf(“a:%xnb:%xn”,a,b); 8请读程序 main() 位操作与文件操作 202 int a=-1; a=a|0377; printf(“%d,%on”,a,a); 以上程序片段的输出结果是 ( 【8】 ) 。 9设 x 是一个整数(16bit) ,若要通过 x|y 使 x 低 8 位置 1,高 8 位不变,则 y 的八进制数是 ( 【9】 ) 。 10以下程序用来统计文件中字符个数。请填空。 (2002.04) #include stdio.h main() FILE *fp; long num=0L; if(fp=fopen(fname.dat,r)=NULL) pirntf(Open errorn); exit(0); while( ( 【10】 ) ) fgetc(fp); num+; printf(num=%1dn,num-1); fclose(fp); 11以下程序段打开文件后,先利用 fseek 函数将文件位置指针定位在文件末尾,然后调用 ftell 函数返回当前文件位置指针的具体位置,从而确定文件长度,请填空。 (2001.09) FILE *myf; ling f1; myf= 【11】 (test.t,rb); fseek(myf,0,SEEK_END); f1=ftel(myf); fclose(myf); printf(%dn,f1); 12下面程序把从终端读入的文本(用作为文本结束标志)输出到一个名为 bi.dat 的新文件中。请 填空。 (2001.04) #include stdio.h FILE *fp; char ch; if( (fp=fopen ( 【12】 ) )= = NULL)exit(0); while( (ch=getchar( ) !=) fputc (ch,fp); fclose(fp); 13下面的程序用来统汁文件中字符的个数,请填空 。 #include main() FILE*fp; long num=0; if(fp=fopen(“fname.dat,”r”)= =NULL) printf (Cant open file:!n); exit(0); while ( 【13】 ) 第 10 章 位操作与文件操作 203 fgetc (fp);num+; printf (“num=%dn” ,num); fclose(fp); 14以下程序由终端键盘输入一个文件名,然后把从终端键盘输入的字符依次放到该文件中,用 0 作 为结束输入的标志。请填空。 #include main( ) FILE *fp; char ch,fname10; printf (Input the name of filen”); gets (fname); if(fp= ( 【14】 ) )= =NULL) printf( Can not openn”); exit(0) ; printf (Enter datan”); while (ch=getchar()!=#) fputc( ( 【15】 ) ,fp); fclose(fp); 15下面程序的功能是:从键盘上输入个字符串,把该字符串中的小写字母转换成大写字母,输 出到文件 test.txt 中,然后从该文件读出字符串并显示出来,请填空。 (1998.9) #include main() FILE *fp; char str100; int i=0; if(fl=fopen(“test, txt”, ( 【16】 ) )=NULL) printf(“Can not open this file.n); exit(O); printf(“Input a string: n); gets(str); while(stri) if(stri =a&stri=z) stri= ( 【17】 ) ; fputc(stri, fp); i+; fclose(fp); fp=fopen(“test.txt”, ( 【18】 ) ); printf(str, 100, fp); fclose(fp); 16下面程序把从终端读人的 10 个整数以二进制方式写到个名为 bi.dat 的新文件中, 请填空。 (1999.04) 位操作与文件操作 204#include FILE *fp; main () int i, j; if(fp=fopen(( 【19】 ) , wb)= =NULL) exit(0); for(i=0; i10; i+) scanf(“%d, &j); fwrite(&j, sizeof(int), 1, ( 【20】 ) ); fclose(fp); 三、参考答案 (一) 选择题参考答案: 1D 2A 3B 4D 5D 6B 7B 8A 9B 10D 11A 12D 13B 14C 15B 16C 17D 18B 19 (1)D(2)C 20A (二) 填空题参考答案: 1 【1】x=11, y=17, z=11 2 【2】10000010 3 【3】59 4 【4】11110000 5 【5】a=a&b 6 【6】x=xy-2 或 x=x(y-2) 7 【7】a:9a b:ff65 8 【8】-1,177777 9 【9】0377 10 【10】 !feof(fp) 11 【11】fopen 12 【12】 bi.dat,w 或 bi.dat,w+ 或 bi.dat,wb+ 13 【13】 (feof(fp) 14 【14】 fopen(fname,”w”) 【15】ch 15 【16】 “w” 【17】 stri-32 【18】 ”r” 16.【19】 “bi.dat” 【20】 fp
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号