13.2.1 按位运算
按位运算,即把整数当做二进制进行运算。
| ·& | 按位的与 |
| ·| | 按位的或 |
| ·~ | 按位取反 |
| ·<< | 左移 |
| ·>> | 右移 |
按位与 &
如果(x)_i==1且(y)_i==1,那么(x&y)_i=1(第i位)否则=0
如:
0101 1010 5A
1000 1100 8C 做运算后:
0000 1000 08
按位与的应用:
-
让某一位或某些位=0,如x & 0xFE(1111 1110) 会让最后一位变为0
-
取某个数中的某一段:如x & 0xFF (在32位int中是 0000 0000 0000 0000 0000 0000 1111 1111)这样只会留下最后8位
按位或
应用: -
使得某一位/某几位变为1: x | 0x01
-
把两个数拼起来: 0x00FF | 0xFF00
按位取反:0变为1,1变为0
和补码不太一样,补码是用1 0000 0000-该数。可以试下(char)~c和(char)-c的值。
逻辑运算,相当于把所有非0值变为1后做按位运算。
因此还是有不同的,如果忘记逻辑运算是两个&|的话就会出问题。
按位异或^,两位相等结果为0,两位不等结果为1.
对同一个值做两次异或,还是原来的值。可以拿来做加密的编码,也可以判断两段码是否相等。
13.2.2 移位运算
i<<j:i中所有位向左移动j个位置,右边填入0
所有小于int的类型,移位以int的方式做,结果是int。
往左移1位就等价于乘了2.最多移动多少位取决于int的大小。x<<1
右移相当于/2。
对于小于int的类型,移位以int的方式做,且结果是int;
对于unsigned类型,左边填0
对于signed类型,左边填入原来的最高位(判断符号的01),保持符号不变。而往左移动的时候是不管符号位的。
移位的位数不要用负数,这是没有定义的行为!
13.2.3 位运算例子
有什么用处?
例1:输出一个数字的二进制
unsigned后面没有跟类型,则是默认为unsigned int。
mask依次是
1000 0000
0100 0000
0010 0000
…

这样每一位依次取余,看每一位。
另外一件事:做单片机时常遇到这样的特殊功能寄存器(SFR)

怎么把对应比特置为0或1?

第几位就是1u<<几
如SBS是1,左移2位是100
PE是1,左移3位是1000
100
1000
1100(或后得到的结果)
用或使某些比特为1,用和使某些比特为0。
13.2.4 位段
在SFR表中可知,有的也不止一个比特。但之前的技巧只能控制一个比特。
如何控制多个比特?位段,把一个int的若干位组合成一个结构。

冒号后面的数字表示 该成员占几个比特。

prtBin函数就是刚刚看过的输出二进制位。
输出:sizeof(uu)=4
二进制输出后五位10010
当我们把uu.trailing=0注释掉后,sizeof(uu)没变,但是二进制位输出变了。后五位仍然是10010,前面没有赋初值(没有让trailing=0),是乱七八糟的0和1.
当我们int trailing=32,仍然让uu.trailing=0,这时sizeof(uu)=8(所有位数加起来超过了32,所以用两个int来表达)二进制输出仍然只有后五位10010.
位段可以直接用位段的成员名称来访问,比移位、与、或还要方便。
编译器会安排其中的位的排列,不具有可移植性(比如老师的例子是从最右边排起,可能自己试验时会从最左边排。)所需要的位超过一个int时会安排多个int。
总而言之,位段是操作和硬件相关的底层操作。
本文详细介绍了位运算,包括按位与、或、取反及移位运算,并提供了实例说明其在处理二进制数据、设置和清除位、加密编码等方面的作用。位移运算中讲解了左移和右移的规则,以及不同数据类型的位移处理方式。同时,文章探讨了位段的概念,用于控制多位组合,方便地操作硬件相关的底层寄存器。位段的使用虽不具可移植性,但在特定场景下能提高效率。
3662

被折叠的 条评论
为什么被折叠?



