单片机的C语言中位操作用法 在对单处机进行编程的过程中,对位的操作是经常遇到的。C51对位的操控能力是非常强大
的。从这一点上,就可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点。
这也是在各个领域中都可以看到C的重要原因。在这一节中将详细讲解C51中的位操作及其应
用。
、位运算符
C51提供了几种位操作符,如下表所示: 运算符 含义 运算符 含义 & 按位与 ~ 取反 | 按位或 << 左移 ^ 按位异或 >> 右移
)“按位与”运算符(&)
参加运算的两个数据,按二进位进行“与”运算。原则是全1为1,有0为0,即:&=;
&=;&=;&=;如下例:
a=&; //a=(0b 0101) & (0b 0011) =0b 0001 =1
那么如果参加运算的两个数为负数,又该如何算呢?会以其补码形式表示的二进制数来
进行与运算。
a=-&-; //a=(0b 1011) & (0b1101) =0b 1001 =-7
在实际的应用中与操作经常被用于实现特定的功能:
a.清零
“按位与”通常被用来使变量中的某一位清零。如下例:
a=0xfe; //a=0b 11111110
a=a&0x55;//使变量a的第1位、第3位、第5位、第7位清零 a= 0b 01010100
b.检测位
要知道一个变量中某一位是‘ ’还是‘’,可以使用与操作来实现。
a=0xf5; //a=0b 11110101
result=a&0x08; //检测a的第三位,result=0
c.保留变量的某一位
要屏蔽某一个变量的其它位,而保留某些位,也可以使用与操作来实现。
a=0x55; //a=0b 01010101
a=a&0x0f; //将高四位清零,而保留低四位 a=0x05
)“按位或”运算符(|)
参与或操作的两个位,只要有一个为‘’,则结果为‘’。即有‘’为‘’,全‘’
为‘’。
|=; |=; |=; |=;
例如:
a=0x30|0x0f; //a=(0b00110000)|(0b00001111)=(0b00111111)=0x3f
“按位或”运算最普遍的应用就是对一个变量的某些位置‘’。如下例:
a=0x00; //a=0b 00000000
a=a|0x7f; //将a的低7位置为1,a=0x7f
)“异或”运算符(^)
异或运算符^又被称为XOR运算符。当参与运算的两个位相同(‘’与‘’或‘’
与‘’)时结果为‘’。不同时为‘’。即相同为0,不同为1。
^=; ^=; ^=;^=;
例如:
a=0x55^0x3f; //a=(0b01010101)^(0b00111111)=(0b01101010)=0x6a
异或运算主要有以下几种应用:
a.翻转某一位
当一个位与‘’作异或运算时结果就为此位翻转后的值。如下例:
a=0x35; //a=0b00110101
a=a^0x 0f; //a=0b00111010 a的低四位翻转
关于异或的这一作用,有一个典型的应用,即取浮点的相反数,具体的实现如下:
f=1.23; //f为浮点型变量 值为1.23
f=f*-; //f乘以-1,实现取其相反数,要进行一次乘运算
f=1.23;
((unsigned char *)&f)[]^=0x80; //将浮点数f的符号位进行翻转实现取相反数
b.保留原值
当一个位与‘’作异或运算时,结果就为此位的值。如下例:
a=0xff; //a=0b11111111
a=a^0x0f; //a=0b11110000 与0x0f作异或,高四位不变,低四位翻转
c.交换两个变量的值,而不用临时变量
要交换两个变量的值,传统的方法都需要一个临时变量。实现如下:
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; //采用异或实现变量对调
}
从上例中可以看到异或运算在开发中是非常实用和神奇的。
)“取反”运算符(~)
与其它运算符不同,“取反”运算符为单目运算符,即它的操作数只有一个。它的功能
就是对操作数按位取反。也就是是‘’得‘’,是‘’得‘’。
~=; ~=;
如下例:
a=0xff; //a=0b11111111
a=~a; //a=0b00000000
a.对小于0的有符号整型变量取相反数
d=-;//d为有符号整型变量,赋值为-1,内存表示为0b 11111111 11111111
d=~d+; //取d的相反数,d=1,内存表示0b 00000000 00000001
此例运用了负整型数在内存以补码方式来存储的这一原理来实现的。负数的补码方式是
这样的:负数的绝对值的内存表示取反加1,就为此负数的内存表示。如-23如果为八位有
符号整型数,则其绝对值23的内存表示为0b00010111,对其取反则为0b11101000,再加1
为0b11101001,即为0XE9,与Keil仿真结果是相吻合的:
b.增强可移植性
关于“增强可移植性”用以下实例来讲解:
假如在一种单片机中unsigned char类型是八个位(1个字节),那么一个此类型的变量
a=0x67,对其最低位清零。则可以用以下方法:
a=0x67; //a=0b 0110 0111
a=a&0xfe; //a=0b 0110 0110
上面的程序似乎没有什么问题,使用0xfe这一因子就可以实现一个unsigned char型的
变量最低位清零。但如果在另一种单片机中的unsigned char类型被定义为16个位(两个字
节),那么这种方法就会出错,如下:
b=0x6767; //假设b为另一种单片机中的unsigned char 类型变量,值为0b 0110 0111 b=b&0xfe; //如果此时因子仍为0xfe的话,则结果就为0b 0000 0000 0110 0110 即
0x0066,而与0x6766不相吻合
上例中的问题就是因为不同环境中的数据类型差异所造成的,即程序的可移植性不好。
对于这种情况可以采用如下方法来解决:
a=0x67; //a=0b 0110 0111
a=a&~; //在不同的环境中~1将自动匹配运算因子,实现最后一位清零 a=0x66 其中
~1为 0b
b=0x6767; //a=0b 0110 0111 0110 0111
b=a&~; //~1=0b 1111 1111 1111 1110,b=0b 0110 0111 0110 0110 ,即0x6766
)左移运算符(<<)
左移运算符用来将一个数的各位全部向左移若干位。如:
a=a<<
表示将a的各位左移2位,右边补0。如果a=(0x22或0b00100010),左移2位得
0b10001000,即十进制的136。高位在左移后溢出,不起作用。
从上例可以看到,a被左移2位后,由34变为了136,是原来的4倍。而如果左移1
位,就为0b01000100,即十进制的68,是原来的2倍,很显然,左移N位,就等于乘以了
2N。但一结论只适用于左移时被溢出的高位中不包含‘
’的情况。比如:
a=; //a=0b 0100 0000
a=a<<; //a=0b 0000 0000
其实可以这样来想,a为unsigned char型变量,值为64,左移2位后等于乘以了4,即
64X4=,而此种类型的变量在表达256时,就成为了0x00,产生了一个进位,即溢出了
一个‘ ’。
在作乘以2N这种操作时,如果使用左移,将比用乘法快得多。因此在程序中适应的使
用左移,可以提高程序的运行效率。
)右移运算符
右移与左移相类似,只是位移的方向不同。如:
a=a>>
表示将a的各位向右移动1位。与左移相对应的,左移一位就相当于除以2,右移N位,
就相当于除以2N。 在右移的过程中,要注意的一个地方就是符号位问题。对于无符号数右移时左边高位移
和‘’。对于有符号数来说,如果原来符号位为‘’,则左边高位为移入‘’,而如果
符号位为‘’,则左边移入‘’还是‘’就要看实际的编译器了,移入‘’的称为“逻
辑右移”,移入‘’的称为“算术右移”。Keil中采用“算术右移”的方式来进行编译。
如下:
d=-; //d为有符号整型变量,值为-32,内存表示为0b 11100000
d=d>>;//右移一位 d为 0b 11110000 即-16,Keil采用"算术逻辑"进行编译
)位运算赋值运算符
在对一个变量进行了位操作中,要将其结果再赋给该变量,就可以使用位运算赋值运算
符。位运算赋值运算符如下:
&=, |=,^=,~=,<<=, >>=
例如:a&=b相当于a=a&b,a>>=2相当于a>>=。
)不同长度的数据进行位运算
如果参与运算的两个数据的长度不同时,如a为char型,b为int型,则编译器会将二
者按右端补齐。如果a为正数,则会在左边补满‘’。若a为负数,左边补满‘’。如果
a为无符号整型,则左边会添满‘’。
a=0x00; //a=0b 00000000
d=0xffff; //d=0b 11111111 11111111
d&=a; //a为无符号型,左边添0,补齐为0b 00000000 00000000,d=0b 00000000

单片机的C语言中位操作用法2的更多相关文章

  1. 单片机的C语言中位操作用法

    在对单处机进行编程的过程中,对位的操作是经常遇到的.C51对位的操控能力是非常强大的.从这一点上,就可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点.这也是在各个领域中都可以看到C的重要 ...

  2. c语言中 -> 的用法

    ->是一个整体,它是用于指向结构体. 1.换种说法,如果我们在C语言中定义了一个结构体,然后申明一个指针指向这个结构体,那么我们要用指针取出结构体中的数据,就要用到"->&quo ...

  3. struct和typedef struct在c语言中的用法

    在c语言中,定义一个结构体要用typedef ,例如下面的示例代码,Stack sq:中的Stack就是struct Stack的别名. 如果没有用到typedef,例如定义 struct test1 ...

  4. C语言中动态分配数组

    如何动态的定义及使用数组呢?记得一般用数组的时候都是先指定大小的.当时问老师,老师说是不可以的.后来又问了一位教C++的老师,他告诉我在C++里用new可以做到,一直不用C++,所以也不明白.今天在逛 ...

  5. 【转】C语言中动态分配数组

    原文地址:http://blog.chinaunix.net/uid-11085590-id-2914577.html 如何动态的定义及使用数组呢?记得一般用数组的时候都是先指定大小的.当时问老师,老 ...

  6. c语言中的位移位操作

    先要了解一下C语言里所有的位运算都是指二进制数的位运算.即使输入的是十进制的数,在内存中也是存储为二进制形式. “<<”用法: 格式是:a<<m,a和m必须是整型表达式,要求m ...

  7. C语言中关于scanf函数的用法

    scanf()函数的控制串 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化 ...

  8. JAVA语言中冒号的用法

    近来由于本人要介入android平台的开发,所以就买了本JAVA语言的书学习.学习一段时间来,我的感觉是谭浩强就是厉害,编写的<C编程语言>系列丛书不愧是经典.书中对C语言的介绍既系统又全 ...

  9. Go语言中异常处理painc()和recover()的用法

    Go语言中异常处理painc()和recover()的用法 1.Painc用法是:用于抛出错误.Recover()用法是:将Recover()写在defer中,并且在可能发生panic的地方之前,先调 ...

随机推荐

  1. Dubbo Spring Cloud Motan

    跨语言统一治理.Golang,谈谈另辟蹊径的开源RPC框架Motan_搜狐科技_搜狐网 https://www.sohu.com/a/207389967_467759

  2. SVD分解的理解

    对称阵A 相应的,其对应的映射也分解为三个映射.现在假设有x向量,用A将其变换到A的列空间中,那么首先由U'先对x做变换: 由于正交阵“ U的逆=U‘ ”,对于两个空间来讲,新空间下的“ 基E' 坐标 ...

  3. java中Integer在JDK1.6和JDK1.7中的区别

    运行下面这段代码: System.out.println(Integer.valueOf("127")==Integer.valueOf("127")); Sy ...

  4. Mac下eclipse的快捷键

    一.Command类 Command+1 快速修复 Command+d 删除当前行 Command+Option+↓ 复制当前行到下一行 Command+Option+↑ 复制当前行到上一行 Comm ...

  5. PAT 天梯赛 L2-013. 红色警报 【BFS】

    题目链接 https://www.patest.cn/contests/gplt/L2-013 思路 可以通过图的连通块个数来判断 假如 一座城市的失去 改变了其他城市之间的连通性 那么 这座城市本来 ...

  6. jsp报An error has occurred. See error log for more details. Argument not valid错误

    An error has occurred. See error log for more details. Argument not valid 翻译过来是:一个错误已经发生.看到更多的细节错误日志 ...

  7. rkhunter和chkrootkit

    今天继续检查我的Linux,所以下来rkhunter和chkrootkit一个一个来,下面只记录命令,少些说明不截图了. 1.rkhunter #cd /temp #wget http://downl ...

  8. 采用个hook技术对writefile函数进行拦截(2)

    http://www.cnblogs.com/zhxfl/archive/2011/11/03/2233846.html 这个是笔者之前写过的WriteFile HOOK代码 必须补充对这几个函数的H ...

  9. 洛谷P4013数字梯形问题——网络流24题

    题目:https://www.luogu.org/problemnew/show/P4013 最大费用最大流裸题: 注意:在第二种情况中,底层所有点连向汇点的边容量应该为inf,因为可以有多条路径结束 ...

  10. 使用Node.js实现简单的网络爬取

    由于最近要实现一个爬取H5游戏的代理服务器,隧看到这么一篇不错的文章(http://blog.miguelgrinberg.com/post/easy-web-scraping-with-nodejs ...