位运算的基本规则
在串行通信的过程中,常涉及数据帧的解码与位运算,这里将集中讲解位运算的理解————位运算是计算机科学中的一种基本运算,它主要是对二进制位进行操作。
参考链接:https://blog.csdn.net/qq_39151563/article/details/108305105,内容大部分都是这篇文章中的,下面给出一些记录与理解。
1、常见的位运算
我们在计算时,一般使用的是 32位的int 类型(在个人计算机中,int一般为32位)。
在 n 位二进制数中,我们一般称最低位为第0位,最高位为n − 1位,总右到左依次是第0 , 1 , 2 , ⋯ , n − 1 位,如下图所示
在使用的过程中,涉及位运算的运算符如下表所示:
符号 | 描述 | 运算规则 | 举例 |
& | 与 | 将参与运算的两个二进制数进行与运算(&),如果两个二进制位都是1,则与运算的结果为1,其他全都为0。(0与任意数N&运算都是0) | a&b |
| | 或 | 将参与运算的两个二进制数进行或运算(|),两个二进制位只要其中1个是1 ,那么就是1,如果2个二进制位都是0则表示0。(0与任意数N|运算都是任意数N) | a|b |
^ | 异或 | 将参与运算的两个二进制数进行^异或运算,如果2个二进制位都是0或者都是1,那么就是0,如果两个二进制位不同,则为1。 | a^b |
~ | 取反 | 一元操作符,按位取反。每个二进制位上都取相反值,1变成0,0变成1。 | ~a |
<< | 左移 | 将一个数各二进制位全部向左移动若干位,左移运算没有有符号和无符号左移动,在左移时,移除高位的同时在低位补0 | a<<2 |
>> | 右移 | 又称为有符号右移。将一个数各二进制位全部向右移动若干位,若参与运算的数字为正数,则在高位补0;若为负数,则在高位补1。 | a>>2 |
1.1、左移
左移是将所有二进制位向左移动 n 位(对于32位值n范围是[0,31])。移动后,最左边的 n 个二进制位将因被移出边界而丢弃,移动后最右边空出来的二进制位补0。
对于32位的int型值,如果移动位数超出 32 位,将会被对32取模,如移动 35 位,将变成移动 3 位( 35 % 32 = 3)。所以左移32位并不会变为0,而是相当于移动 0 位,值不变。
技巧:左移1位相当于在该数乘以2,左移2位相当于该数乘以2*2
在没有发生 溢出 和 环绕 的情况下,n左移一位后的值相当于 2n。
溢出:指的是计算结果超出有符号数存储的范围。
环绕:指的是计算结果超出无符号数存储的范围。
1.2、有符号右移
有符号整数左边的最高位为符号位,代表着数的正负,负数最高位为1,正数和0的最高位为0。
有符号数右移时,最右边的位丢弃,最左边的空位补上原来的最高位。有符号右移又叫 算术右移,在算术上相当于是值除以2的结果。
对于有符号数来说,算术右移的结果等于原数除以2再向下取整(公式中,|x|为对x向下取整):
n >> 2 = |a/2|
如负数 -3 >> 1 = -2,正数 3 >> 1 = 1。
1.3、无符号右移
无符号数没有符号位,所有位都作为二进制的数值位。右移时,最右边的位丢弃,最左边的位补0。无符号右移又叫逻辑右移。
2、整数类型之间的转换
C/C++ 中的整数类型有 char
, short
, int
, long
和 long long
,这里按类型的位数进行区分,类型的位数越高,那么取值范围就越大,类型就越高级。
一个变量的类型无论是有符号还是无符号,其 存储的二进制内容都是不变的,不同的对这些二进制位的解释方法。
无符号数把最高位作为一个普通的位,而有符号数把最高位作为符号位,相当于改变了最高位的权重,n位无符号数最高位权重是2n-1,而有符号数最高权重是 -2n-1
如一个八位的无符号数 a,二进制表示为1000 0001,最高位权重是128,最低位权重是1,因此值为 129。当把 a 转成有符号数时,二进制表示依然为 1000 0001,
但此时最高位的含义已经发生了变化,相当于权重 − 128,此时值为 − 127。
2.1、低级类型向高级类型转换
在整数类型之间的转换中,如果一个变量由 低级类型向 高级类型转换,那么转换时低位不变、高位根据变量 原先的类型 是无符号还是有符号使用不同的方式进行填补
变量原先的类型 | 高位填补方式 |
无符号类型 | 用0填补 |
有符号类型 | 用符号位进行填补 |
2.2、高级类型向低级类型转换
在整数类型之间的转换中,如果一个变量由 高级类型 向低级类型转换,那么二进制位将会被 截断 ,高位丢弃,只保留低位作为转换后的二进制内容。
最后的值是多少则根据转换后是有符号类型还是无符号类型对二进制位进行解析。
如下图所示,一个16位类型的值转成8位类型,直接截取低8位作为转换后的二进制内容 1010 1101,如果这个8位类型是无符号,那么数值为 173,如果是有符号类型,则是 -83。
3、常用的位运算操作
一个字节共8位,最低位是第0 位,最高位是第7 位。如果是32位的 int 型,则最低位为第0 位,最高位为第31位。
1 //取低8位
2 a & 0xFF
3
4 //取第8至第15位
5 a & 0xFF00
6
7 //取高16位
8 a & 0xFFFF0000
9
10 //取偶数位
11 a & 0x55555555
掩码:一串二进制代码对目标字段进行位与运算,屏蔽当前的输入位。
示例:
取32位数中第三个字节的值。第三个字节从第24位开始的8位,所以可以将原数右移24位,然后和低8位掩码0xFF 做 按位与运算 即可得到对应的值。
1 (a >> 24) & 0xFF; // 一个字节8个位