收藏 分享(赏)

C语言中的位操作符.docx

上传人:hyngb9260 文档编号:6356577 上传时间:2019-04-09 格式:DOCX 页数:13 大小:21.06KB
下载 相关 举报
C语言中的位操作符.docx_第1页
第1页 / 共13页
C语言中的位操作符.docx_第2页
第2页 / 共13页
C语言中的位操作符.docx_第3页
第3页 / 共13页
C语言中的位操作符.docx_第4页
第4页 / 共13页
C语言中的位操作符.docx_第5页
第5页 / 共13页
点击查看更多>>
资源描述

1、 C 语言中的位操作符因为 C 语言的设计目的是取代汇编语言,所以它必须支持汇编语言所具有的运算能力,所以 C 语言支持全部的位操作符(Bitwise Operators) 。位操作是对字节或字中的位( bit)进行测试、置位或移位处理,在对微处理器的编程中,特别适合对寄存器、I/O 端口进行操作。因而本节将对此作比较详细地介绍。6 种位操作符的形式与含义如下:& :按位 “与” (AND ) ;| :按位“或” (OR ) ; :按位“异或” (XOR ) ; :“取反” (NOT ) ; :数据右移; :数据左移;1) 按位“与”运算按位“与”运算符 & 的作用是对运算符两侧以二进制表达的

2、操作数按位分别进行“与”运算,而这一运算是以数中相同的位(bit)为单位的。操作的规则是:仅当两个操作数都为 1 时,输出的结果才为 1,否则为 0。例如:a = 0x88,b = 0x81,则 a & b 的运算结果如下:0x88 1000 1000 a 数& 0x81 1000 0001 b 数= 1000 0000其中,& 运算符让 a 数 0x88 与 B 数 0x81 的 1 位与 1 位、2 位与 2位7 位与 7 位分别相“与” 。由于“与” 运算的操作规则是,两个操作数中各位只要有 1 个为 0,其结果中对应的位就为 0。而 a 数与 b 数中只有最高位(第 7 位)均为 1,

3、因而该位结果为 1,其它各位结果都为 0。通常我们可把按位“与”操作 & 作为关闭某位(即将该位置 0)的手段,例如我们想要关闭 a 数中的第 3 位,而又不影响其它位的现状,可以用一个数 0xF7,即二进制数 1111 0111 去与 a 数作按位“与”运算:0x88 1000 1000 a 数& 0xF7 1111 0111 屏蔽数= 1000 0000注意,这个数除第 3 位为 0 外,其它各位均为 1,操作的结果只会将 a 数中的第 3 位置 0,而 a 数的其它位不受影响。也就是说,若需要某个数的第 n 位关闭,只需要将该数与另一个数按位相与,另一个数除了相应的第 n 位为 0 外,

4、其它各位都为 1,以起到对其它各位的屏蔽作用。上面的运算可以用 a = a &(0xF7 ) 来表示,也可以用 a & =(0xF7) 来表达。这两个表达式功能是相同的(见上节“复合赋值运算符”部分) ,但在源程序代码中常常见到的以第二种形式为多。2) 按位“或”运算按位“或” 运算符 | 的作用是对运算符两侧以二进制表达的操作数按位分别进行“或”运算,而这一运算是以数中相同的位(bit)为单位的。操作的规则是:仅当两个操作数都为 0 时,输出的结果才为 0,否则为 1。例如:a = 0x88,b = 0x81,则 a | b 的运算结果如下:0x88 1000 1000 a 数| 0x81

5、1000 0001 b 数= 1000 1001通常我们可把按位“与”操作 & 作为置位(即将该位置 1)的手段,例如我们想要将 a 数中的第 0 位和 1 位置 1,而又不影响其它位的现状,可以用一个数 0x03,即二进制数 00000011 去与 a 数作按位“或”运算:0x88 1000 1000 a 数| 0x03 0000 0011 屏蔽数= 1000 1011注意,这个数除第 0、 1 位为 1 外,其它各位均为 0,操作的结果只会将 a 数中的第 0、1 位置 0,而 a 数的其它位不受影响。也就是说,若需要某个数的第 n 位置 1,只需要将该数与另一个数按位相“或” ,另一个数

6、除了相应的第 n 位为 1 外,其它各位都为 0,以起到对其它各位的屏蔽作用。上面的运算可以用 a = a | (0xF7 ) 来表示,也可以用 a | =(0xF7 ) 来表达。3) 按位“异或”运算按位“异或”运算符 的作用是对运算符两侧以二进制表达的操作数按位分别进行“异或”运算,而这一运算是以数中相同的位(bit)为单位的。异或运算操作的规则是:仅当两个操作数不同时,相应的输出结果才为 1,否则为 0。例如:a = 0x88,b = 0x81,则 a b 的运算结果如下:0x88 1000 1000 a 数 0x81 1000 0001 屏蔽数= 0000 1001按位“异或”运算 具

7、有一些特殊的应用,介绍如下: 按位“异或”运算可以使特定的位取反例如:我们想让 a 数中的最低位和最高位取反,只要用 0x81,即二进制数 10000001 去与它作按位 “异或”运算,其运算结果同上式。经过操作后,最高位的值已经由 1 变 0,而最低位的值也已经由 0变 1,起到了使这两位翻转的效果。其它位的状态保持不变。可以看到,这个数除最低位、最高位为 1 外,其它各位均为 0,操作的结果只会将 a 数中的第 0、7 位取反,而 a 数的其它位不受影响。也就是说,若需要某个数的第 n 位取反,只需要将该数与另一个数按位相“异或” ,另一个数除了相应的第 n 位为 1 外,其它各位都为0,

8、以起到对其它各位的屏蔽作用。上面的运算可以用 a = a (0x81 ) 来表示,也可以用 a =(0x81 ) 来表达。 直接交换两个变量的值例如,若有变量 a = 3,b = 4,想要交换它们的值,可以做如下一组操作:a = bb = aa = b首先,a = b:a 0000 0011 b 0000 0100a = 0000 0111其次,b = a:b 0000 0100 a 0000 0111b = 0000 0011最后,a = b:a 0000 0111 b 0000 0011a = 0000 0100这样,a、b 两个变量中的值就进行了对调。4) “取反”运算“取反”运算符 的

9、作用是将各位数字取反:所有的 0 置为 1,1置为 0。例如:1001 0110 取反后为 0110 1001。5) 数据右移数据右移操作符 将变量的各位按要求向右移动若干位。右移语句的通常形式是:variable 右移位数如:a = 1111 0000;进行 a = a 2 操作后,a = 0011 1100。6) 数据左移数据左移操作符 将变量的各位按要求向左移动若干位。左移语句的通常形式是:variable 左移位数如:a = 1111 0000;进行 a = a 2 操作后,a =1100 0000。无论是左移还是右移,当某位从一端移出时,另一端出现的空白将以从外面移入的 0(某些计算

10、机是送 1,详细内容请查阅相应 C 编译程序用户手册)来补充。这说明,移位不同于循环,从一端移出的位并不送回到另一端去,移去的位永远丢失了,同时在另一端只能补上相应位数的 0。移位操作可用于整数的快速乘除运算,左移一位等效于乘 2,而右移一位等效于除以 2。如:x = 7, 二进制表达为:0000 0111,x 1 0000 1110,相当于: x =2*7=14,x 3 0111 0000,相当于: x=14*2*2*2=112x 2 1100 0000, x= 192在作第三次左移时,其中一位为 1 的位移到外面去了,而左边只能以 0 补齐,因而便不等于 112*2*2=448,而是等于

11、192 了。当 x 按刚才的步骤反向移动回去时,就不能返回到原来的值了,因为左边丢掉的一个 1,再也不能找回来了:x 2 0011 0000, x=48x 3 0000 0110 x=48/8=6x 1 0000 0011 x=6/2=3移位操作还可以配合其它位操作夫对寄存器或者数据 I/O 接口的各个位进行设置、检测,具体方法见下一节。2.位操作符的一些实用方法介绍1) 学会应用复合运算符如前面所介绍的,位操作运算符可以和赋值运算符“=”一起组成复合运算符。即如下 5 个:= 、 =、&=、=、|=其中,x = y,相当于 x = x y;x = y,相当于 x = x y;x & = y,

12、 相当于 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

13、 位置 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。即:

14、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 = 0x87 1000 0111& 0x80 1000

15、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,再做按位 “与”

16、操作。这样的操作结果是将指定的第 7位清零,其它各位保持不变。 PORTA | = (17)等价于 PORTA = PORTA | (17 ) ,这里也是先执行括号中的 17操作,将 0x01 左移 7 位,其值变成 0x80,再将它与 PORTA 做按位“或” 。若操作前 PORTA 的初始值为 0x07,则:PORTA 0000 0111| 0x80 1000 0000PORTA = 1000 0111该操作将最高位置 1,其它各位保持不变。要注意的是,这条指令与 PORTA = (17) 相比,虽然都可以使指定的某一位置 1,但它们有着不同之处。PORTA = (17 ) 执行后,虽然某

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) 这样的指令一次将设第

18、 8、5 和 1 位置 1,但又不影响到其它位的状态。在实际应用中,经常利用 PORTA & = ( 1 n) 这条指令将寄存器的任意位清 0,而又不影响其它位的现有状态。比如说,你如果想将第 4 位清 0,就使用 PORTA & = (1 4) 就行了。在启动 nRF905 芯片向空中发送数据时,采用以下函数:void nrf905_TxSend(void)PORTD|=(1TRXCE) ;DelayUs(1) ;/10usPORTD &= (1TRXCE) ;其中让 PORTD 中控制 TRX_CE 信号的那一位先置 1,再清 0,输出一高一低的脉冲信号,就在一个脉冲周期内,完成了一次数据

19、发送。因为在程序的开头已经定义 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) ; /

20、一般先 AM=1 指示地址匹配对while (PIND&(1 DR) )=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 ):P

21、IND 为 PORTD 端口的 8 位引脚的值,PIND& (1 DR)表示让它和(1DR) 亦即和 0000 0100 按位相“与” 。不管 PIND 的其它位为何值,由于和 0 相与,这些位的结果都为 0,我们关心的只有第 2位的状态。由于该位与 1 相与,只要 DR 为高,就会有:PIND xxx x1xx& 0000 0100结果 = 0000 0100结果的第二位的状态为 1,也就是整个表达式 (PIND&(1DR) )= = 0 不成立,语句的逻辑值为 0。若 DR 为低,则有:PIND xxxx x0xx& 0000 0100结果 = 0000 0000也就是整个表达式的结果为 0, (PIND&(1DR) )= = 0 成立,语句的逻辑值为 1。根据括号中逻辑值的情况,while 或者 if 语句再决定程序的流向。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 网络科技 > C/C++资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报