位运算例子
一、常用的方法
借鉴 野火STM32 开发板教程中的内容
1. 变量的某位清零
//定义一个变量 a = 1001 1111 b(二进制数)
unsigned char a = 0x9f;
//对bit 2 清零
a &= ~(1<<2);
//括号中的1左移两位,(1<<2)得二进制数:0000 0100 b
//按位取反,~(1<<2)得 1111 1011 b
//假如a中原来的值为二进制数:a = 1001 1111 b
//所得的数与a作"& 位与"运算,a = (1001 1111 b) & (1111 1011 b),
//经过运算后,a的值a = 1001 1011 b
//a的bit2位被清零,而其它位不变。
2. 变量的某几个连续位清零
//若把a中的二进制位分成2个一组
//即bito、bit1为第0组,
//bit2、bit3为第1组,
//bit4、bit5为第2组,
//bit6、bit7为第3组
//要对第1组的bit2、bit3清零
a &= ~(3<<2*1);
//括号中的 3 左移两位,(3<<2*1)得二进制数:0000 1100 b
//按位取反,~(3<<2*1)得 1111 0011 b
//假如 a 中原来的值为二进制数:a = 1001 1111 b
//所得的数与a作"& 位与"运算,a = (1001 1111 b) & (1111 0011 b),
//经过运算后,a的值a = 1001 0011 b
//a的第1组的bit2、bit3被清零,而其它位不变。
//上述(~(3<<2*1)中的(1)即为组编号;如清零第3组bit6、bit7此处应为3
//括号中的(2)为每组的位数,每组有2个二进制位;若分成4个一组,此处即为4
//括号中的(3)是组内所有位都为1时的值;若分成4个一组,此处即为二进制数"1111 b"
//例如对第2组bit4、bit5清零
a &= ~(3<<2*2);
3. 对变量的某几位进行赋值
//a = 1000 0011 b
//此时对清零后的第2组bit4、bit5设置成二进制数“01 b”
a |= (1<<2*2);
//a=1001 0011 b,成功设置了第2组的值,其它组不变
4.对变量的某位取反
//a = 1001 0011 b
//把bit6取反,其它位不变
a^=(1<<6);
//a=1101 0011 b
二、应用例子
1. 二进制置各种状态值
比如以一个16位的二进制表示各种状态值。例如第一位代码置1代表小车急停按下,置0代表解除小车急停。
enum StatusTypes{
AGV_STOP_BUTTON_PRESSED=0,//小车急停按下
AGV_UNKNOWN_ERROR=1,//小车未知错误
CHARGE_CONNECTED_ERROR=2,//充电连接错误
};
void MainWindow::setStatusCode(bool isSet1,StatusTypes statusTypes)
{
if(isSet1)
{
statusCode_=statusCode_|(1<<statusTypes);
}
else
{
statusCode_=statusCode_&(~(1<<statusTypes));
}
qDebug()<<QString("%1").arg(statusCode_,16,2,QLatin1Char('0'));
}
void MainWindow::on_pushButton_clicked()
{
setStatusCode(true,AGV_STOP_BUTTON_PRESSED);
setStatusCode(true,CHARGE_CONNECTED_ERROR);
setStatusCode(false,CHARGE_CONNECTED_ERROR);
}
"0000000000000001"
"0000000000000101"
"0000000000000001"
2. 查看第几位状态值,参数bit第几位推荐使用enum类型,便于维护。
//num 数值 bit 第几位的值 从右边开始数第一位为0,第二位1
int MainWindow::getStatusValue(int num,int bit)
{
return (num >> (bit)) & 1;
}
void MainWindow::on_pushButton_clicked()
{
int16_t num=5;
int status=getStatusValue(num,2);
if(status==1)
{
}
}
3. 置位
#define setbit(x,y) x|=(1<<y) //将X的第Y位置1
#define clrbit(x,y) x&=~(1<<y) //将X的第Y位置0
4. 32位和8位数转换
#include <iostream>
#include <cstdint>
// 分割32位整数为4个8位部分
void splitInt32ToBytes(uint32_t value, uint8_t bytes[4]) {
bytes[0] = (value >> 24) & 0xFF; // 高字节
bytes[1] = (value >> 16) & 0xFF;
bytes[2] = (value >> 8) & 0xFF;
bytes[3] = value & 0xFF; // 低字节
}
// 从4个8位部分合并为32位整数
uint32_t combineBytesToInt32(const uint8_t bytes[4]) {
return (bytes[0] << 24) |
(bytes[1] << 16) |
(bytes[2] << 8) |
bytes[3];
}
//4个8位数转换成32位
uint8_t data[4];
data[0]=0x4E;
data[1]=0x11;
data[2]=0x01;
data[3]=0x40;
uint32_t data32;
//注意此处仅等号,如果写成 "|=" 有时转换成的数会不正确的。如数0x4E 0x11 0x01 0x40在keil上转化成功就不对
data32 = data[0]<<24;
data32 |= data[1]<<16;
data32 |= data[2]<<8;
data32 |= data[3];
5. 两个32位数合成带符号的64位数
uint32_t data1 = 0x12345678;
uint32_t data2 = 0x12345678;
int64_t t1 = (int64_t)(((uint64_t)data1<<32)|data2);
double d1 = t1/10000.0;
qDebug()<<"t1:"<<t1;//t1: 1311768465173141112
qDebug()<<"d1:"<<d1;//d1: 1.31177e+14
//FEDBA987 EDCBA988
uint32_t n1 = 0xFEDBA987;
uint32_t n2 = 0xEDCBA988;
int64_t t21 = (int64_t)(((uint64_t)n1<<32)|n2);
double d21 = t21/10000.0;
qDebug()<<"t21:"<<t21;//-82285766900995704
qDebug()<<"d21:"<<d21;//d21: -8.22858e+12