目录
1.前言
程序中的所有数在计算机内存中都是以二进制补码的形式储存的。而位运算,就是对这些数在内存中的二进制位进行操作。而C语言中位操作符,就是用来实现位运算的符号,以下就是C语言中6种位操作符的符号和功能:
位操作符 | 功能 |
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
<< | 按位左移 |
>> | 按位右移 |
~ | 按位取反 |
注:上述位操作符只能用于整形操作数
2.位操作符
1.按位与&
按位与的定义是:同一二进制位上的数字都是1的话,&的结果为1,否则为0。即1&0=0,0&0=0,1&1=1。任取两个二进制补码按位与得到的结果如下(假设寄存器为8位):
0101 0010
1101 1000 &
0101 0000
其中,位运算是在寄存器中进行,位数不足会先进行整形提升。
2.按位或|
按位或的定义是:同一二进制位上的数字都是0的话,|的结果为0,否则为1。即1&0=1,0&0=0,1&1=1。任取两个二进制补码按位或得到的结果如下:
0101 0010
1101 1000 |
1101 1010
3.按位异或^
按位异或的定义是:同一二进制位上的数字不同的话,^的结果为1,否则为0。即1&0=1,0&0=0,1&1=0。任取两个二进制补码按位异或得到的结果如下:
0101 0010
1101 1000 ^
1000 1010
4.按位左移<<
对于按位左移,无论是有符号数,还是无符号数,都是高位舍弃,低位补0,即逻辑移位。例如:
0101 0010 <<1
1010 0100
1101 1000 <<1
1011 0000
没有溢出的条件下,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
需要注意的是,所有的位运算都是先将内存中存放的二进制位拷贝进寄存器中并在寄存器进行,因此这里的移位运算并未改变内存中变量的值。即a<<1并没有改变a的值,如需改变,需将寄存器中的值写回内存,则应改为a=a<<1。
5.按位右移>>
对于按位右移,当数据类型是有符号数时,右移是低位舍弃,高位补符号位,即算数移位;当数据类型为无符号数,右移是低位舍弃,高位补0,即逻辑移位。例如:
0101 0010 >>1 有符号数
0010 1001
0101 0010 >>1 无符号数
0010 1001
1101 1000 >>1 有符号数
1110 1100
1101 1000 >>1 无符号数
0110 1100
没有溢出的条件下,右移一位相当于除2,右移n位相当于除以2的n次方。
6.按位取反~
按位取反的定义是:将所有的二进制位包括符号位逐位取反,1变0,0变1。即~1=0,~0=1。这里需要注意的是,按位反~与逻辑反!不同,逻辑反是真变假,假变真,在C语言中,0代表假,非0代表真,即!2=0,!3=0。关于按位取反的例子如下:
0101 0010 ~
1010 1101
3.位运算的应用
位运算的应用场景主要在单片机,嵌入式开发中,用于设置寄存器的某个比特位的值来读写寄存器和执行相应功能。
1.设置特定位比特位为1
通过上面位操作符的分析,我们先假设每个比特位值为n,而n|1==1,n|0==n,因此我们可以使用按位或来实现目的,图示如下(第5位置1):
样例代码如下(使用宏定义的方式来实现):
#include<stdio.h>
#define SETBIT(x,n) ((x)|=(1<<(n-1))) //将第n位置1
int main()
{
int x = 10;
SETBIT(x, 5); //0000 0000 0000 0000 0000 0000 0000 1010 在第5位置1
return 0;
}
根据图示,要将第n位置1,则只需将x|1<<(n-1)即可,由于位运算是在寄存器中运算的,所以还需将寄存器的值写回内存,所以需要使用|=号。
2.设置特定位比特位为0
同理,如果我们要置某个比特位为0,由于n&0==0,n&1==n,因此我们可以使用按位与来实现此功能,图示如下(第4位置0):
样例代码如下(使用宏定义的方式来实现):
#include<stdio.h>
#define RESETBIT(x,n) ((x)&=(~(1<<(n-1)))) //将第n位置0
int main()
{
int x = 10;
RESETBIT(x, 4); //0000 0000 0000 0000 0000 0000 0000 1010 在第4位置0
return 0;
}
3.翻转特定位比特位
由于n^1==~n,n^0==n,因此我们可以使用按位异或来实现翻转比特位的功能,图示如下(翻转第6位):
样例代码如下(使用宏定义的方式来实现):
#include<stdio.h>
#define FLIP(x,n) ((x)^=(1<<(n-1))) //将第n位置翻转
int main()
{
int x = 10;
FLIP(x, 6); //0000 0000 0000 0000 0000 0000 0000 1010 在第6位置翻转
return 0;
}
4.逐位显示比特位
由于n&0==0,n&1==n,因此如果我们需要显示某个数第10位比特位,则将其与第10位为1,其余位为0的数按位与。如果最后的结果为0,则说明第10位为0,否则为1,并从高到低逐位循环打印出来。图示如下(显示高位第二位):
样例代码如下(使用函数的方式来实现),将10的二进制补码序列打印出来:
#include<stdio.h>
void ShowBit(int x) //显示比特位
{
int n = sizeof(x) * 8; //求出比特位数
while (n>0)
{
if ((x & (1 << (n - 1))) == 0) //从高到低打印,打印第n位,==优先级比&高
{
printf("0 ");
}
else
printf("1 ");
n--; //准备打印下一位
}
}
int main()
{
int x = 10;
ShowBit(x);
return 0;
}
5.总结
位操作主要用于对某个比特位的设置或者比特位的打印,多用于单片机和嵌入式开发中对寄存器的操作
以上,就是本期的全部内容。
制作不易,能否点个赞再走呢qwq