位逻辑运算符:&(位“与”)、^(位“异或”)、|(位“或”)、~(位“取反”)。
位逻辑运算以位(bit)为单位,1个字节有8个位,每个位有0、1两个取值。1 B = 8 bits
位取反操作
位取反的操作符为“~”,0变成1,1变成0,需要注意的是,位取反运算并不改变操作数的值。在 嵌入式开发中,改变led灯的亮灭常用取反操作符。取反示例:
unsigned char led=15; //00001111
printf(“%d”,~led); //11110000 240
位与运算
位与运算的操作符为&,1 & 1=1 1 & 0=0 0 & 1=0 0 & 0=0;
与0相与结果都为0,与1相与值不变,常用于清零操作。
unsigned char led = 3; //00000011
unsigned char yu=240; //11110000
1将末位清零
#include <stdio.h>
int main(void) {
int led =15; //0000 1111
led=led&~1; //~1=1111 1110
// 00001110
printf("%d",led);
return 0;
2不用%求余数,如求15被4整除的余数,对4整除,一般用于结构体字节对齐,便于内存对齐。
#include<stdlib.h>
int main(void) {
int led =15; //0000 1111
led=led-( led&~3); //( led&~3) 抹除后两位,就能整出4,再相减即可得
printf("%d",led);
return 0;
3.统计二进制整数有多少个1 ,x&x-1,每次减少一个1。
#include<stdlib.h>
int main(void) {
int x=250; //1111 1010
int i=0;
while(x)
{
i++;
x=x&(x-1);
}
printf("%d ",i);
return 0;
}
位或运算
位或运算的操作符为|,将对两个操作数的每一位进行或运算,位“或”运算的准则如下:
1 | 1=1 1 | 0=1 0 | 1=1 0 | 0=0
与1相或都为1,可以让某些位变为1
unsigned char led = 3; //00000011
unsigned char huo=240; //11110000
printf(“%d”,led|huo); //1111 0011 结果为0 243
位异或运算的操作符为^,将对两个操作数的每一位进行异或运算。通俗地讲,如果位“异或”运算的两个位相同(同为0或同为1),结果为0,若两个位不同(一个为0,另一个为1),结果为1,对应的准则为:
1 ^ 1=0 1 ^ 0=1 0 ^ 1=1 0 ^ 0=0
无论是0还是1 与 1 进行异或都会进行逆转实现反转
无论是0还是1 与 0进行异或都不会发生变化
异或运算示例:
unsigned char led =169; //10101001
unsigned char yihuo=15; //00001111
printf(“%d”,led^yihuo); //10100110 166
异或交换两个变量,不借助中间变量
#include <stdio.h>
int main(void) {
unsigned char led =15; //0000 1111
unsigned char yihuo=240; //1111 0000
led=led^yihuo;
yihuo=led^yihuo;
led=led^yihuo;
printf("%d,%d",led,yihuo); //240,15
return0;
}
原理同下数学技巧,不过下面这种会有溢出的风险
#include <stdio.h>
int main(void) {
int led =15;
int yihuo=240;
led = led+yihuo;
yihuo=led-yihuo;
led=led-yihuo;
printf("%d,%d",led,yihuo);
return 0;
}
顾名思义,移位运算就是将某个量中的bits向左或向右移动,该量的值也会相应发生变化,在开灯关灯这个场景中,移位运算的一个重要应用是实现流水灯效果,即按从1到8或从8到1的顺序每次只亮一个灯。
移位运算符:<<(左移)、>>(右移)
1. 移位运算就是将某个量中的bits向左或向右移动,该量的值也会相应发生变化。
移位运算表达式的基本形式为:
A << n; /*左移*/
或
A >> n; /*右移*/
A称为操作数,其必须为数字型变量或数字型常量,此处的数字型包括整型、浮点型和char型,A中存储的0、1序列向左或右移动n位,移动后的值作为整个表达式的输出,执行移位运算并不改变操作数A的值。
2. 左移,左移一位等价于乘2,右边填充为0
#include <stdio.h>
#include<stdlib.h>
int main(void) {
unsigned char ch=1; //0000 0001
for(int i=0;i<8;i++) //char 类型占一个字节共有八位
{
ch=ch<<1; //通过赋值改变操作数
printf("%d ",ch);
}
return 0;
}
结果为:2 4 8 16 32 64 128 0
只有8位,只能移动7位,多了溢出为 1 00000000 ,取后八位,为0
3. 右移,右移一位等价于除以2,按照符号位,正数左边填充0,,负数填充1
#include <stdio.h>
#include<stdlib.h>
int main(void) {
unsigned char ch=128; //1000 0000
for(int i=0;i<7;i++)
{
ch=ch>>1; //移位操作在寄存器中进行,要改变需要赋值
printf("%d ",ch);
}
return 0;
}
结果为64 32 16 8 4 2 1
移位应用
//打印 补码
#include <stdio.h>
int main(void) {
int num=-1; //
int data=1<<31;
for (inti=1;i<=32;i++)
{
printf("%c",(num&data ?'1':'0'));
num<<=1;
if(i%4==0)
{
printf(" ");
}
}
return 0;
}
结果为 1111 1111 11111111 1111 1111 1111 1111
位运算输出浮点数据
#include <stdio.h>
int main(void) {
float num=1.5; //
unsigned char *p=(unsigned char*)#//进行地址转换 ,共享内存
for (int i=3;i>=0;i--)
{
unsigned char chs=p[i];
for(int j=7;j>=0;j--)
{
if(chs&(1<<j))
{
printf("1");
}
else
{
printf("0");
}
}
printf(" ");
}
return 0;
}
结果为 00111111 11000000 00000000 00000000
注意事项
1. 位运算仅仅适用于整数,字符,实数是指数方式表示的,不适用于位运算。
2. 无符号的数据在进行位运算的时候,需要自动进行转换,低字节向高字节转换的时候,会自动填充0
3. 有符号在进行位运算的时候,需要自动进行转换低字节向高字节转换的时候,正数会按照符号位0 会自动填充0,负数会按照符号位1 自动填充1.