目录
标志位
寄存器位段操作
位运算的其他应用
标志位
我们经常都会使用到标志位的操作,来标记是否去实现某个功能。比如冒泡排序中当排序没有完成,始终将一个标志位置位(flag = 1),每次循环开始又会重新清除标志位,再进行遍历。一轮循环结束,程序根据标志位是否被置位来决定是否跳出循环。
然而,在一些比较复杂的情况需要使用到多个标记时,此时使用flag1、flag2、来表示太过于繁琐,因此可以引入位运算的操作。
我们先指定一个char类型(int8_t)的数据,它是由八个字节组成,将每个字节看成一个标志位,则一个char类型的数据可以表示八个标志位,具体操作如下:
//首先我们定义一个枚举,列举出每个操作对应的位
typedef enum{mode1 = 0x01, //0000 0001mode2 = 0x02, //0000 0010mode3 = 0x04, //0000 0100mode4 = 0x08, //0000 1000mode5 = 0x10, //0001 0000mode6 = 0x20 //0010 0000
}mode_t;int main()
{uint8_t flag = 0; //此时没有任何标志//置位操作flag |= mode1; //将mode1添加到flag中,此时flag的最低位置位 0000 0001flag |= mode4; //将第4位置位,此时flag为 0000 1001//也可以这样表示://flag |= (1 << 4); //将1左移四位再相与//判断操作if(flag &= mode1) {} //flag最低位已经置位,与mode1相与结果为真if(flag &= mode2) {} //flag第二位为0,与mode2相与结果为假//去除某种模式flag &= ~mode4; //将第四位清除//也可以这样表示://flag &= ~(1 << 4);}
通过以上操作,可以轻松地通过一个数据表示出需要执行哪几种工作模式,不仅方便高效还增加了可读性。
寄存器位段操作
struct u0{unsigned int leading :3;unsigned int FLAG1: 1;unsigned int FLAG2: 1;int trailing: 27;
};//冒号后面表示这个变量占用几个比特,结构体大小为以上比特之和struct u0 uu;
uu.leading = 2; //010
uu.FLAG1 = 0; //0
uu.FLAG2 = 1; //1
uu.trailing = 0;
//直接通过位段操作整个寄存器//这样表示的uu是一个32比特的数
//其二进制为
//00000000 00000000 00000000 00010010
//这样可以直接通过成员名称访问某些比特,比位运算方便
位运算的其他应用
//快速交换两个变量的值:使用异或运算符(^)可以在不使用临时变量的情况下交换两个变量的值。例如,
a ^= b;
b ^= a;
a ^= b; //此时a、b的值已经交换//快速判断奇偶性:
if(x & 1 == 1) //x是奇数
if(x & 1 == 0) //x是偶数//快速乘除以2的幂次方:对于整数 x,x << n 可以快速将 x 乘以 2 的 n 次方;x >> n 可以快速将 x 除以 2 的 n 次方(向下取整)。x << 3 == x * 2^3x >> 2 == x / 2^2//快速判断是否为2的幂:
if(x & (x - 1) == 0) //x 是2的幂//快速求绝对值:
(x ^ (x >> 31)) - (x >> 31)//快速检查某位是否为1:if((x & (1 << n)) != 0) //检查 x 的第 n 位是否为1。//快速设置某位为1:x |= (1 << n); //将 x 的第 n 位设置为1。//快速清除某位:x &= ~(1 << n); //将 x 的第 n 位清零。//快速取模:
对于整数 x 和 2 的幂次方 y,可以使用 x & (y - 1) 来取模运算 x % y,前提是 y 是2的幂。