常见位运算:
取反~,按位与&,按位或|,按位异或^,逻辑左移<<, 逻辑右移>>,算术左移<<, 算术右移>>
1、用掩码将最低n位置为0
下面这个例子,是将某输入数字的最低11位强制置为0,其他位保持不变。
void BitTest1()
{
uint32_t x = 0xF596DF32;
uint32_t mask = 0xFFFFF800;
x = x & mask;
}
该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:
①使用取反将0置为全1:~0
②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n
使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)
uint32_t mask = (~0) << 11;
2、用掩码保留最低n位,其他位置为0
下面这个例子,是将某输入数字的最低10位的值保留,其他位全部置为0。
void BitTest2()
{
uint32_t x = 0xF596DF32;
uint32_t mask = 0x3FF;
x = x & mask;
}
该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:
①使用取反将0置为全1:~0
②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n
③再次取反,形成低n位为1,其他位为0的掩码:~((~0) << n)
使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)
uint32_t mask = ~((~0) << 10);
3、用掩码取出第m位开始的连续n位的值
下面这个例子,是将某输入数字的bit4~bit14的值保留,其他位全部置为0。(注意此例中最低位为bit0,最高位为bit31)
void BitTest3()
{
uint32_t x = 0xF596DF32;
uint32_t mask = 0x7FF0;
x = x & mask;
}
该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:
①使用取反将0置为全1:~0
②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n
③再次取反,形成低n位为1,其他位为0的掩码:~((~0) << n)
④再次左移m位,形成中间需要的n位为1,其他位为0的掩码:(~((~0) << n)) << m
使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)
uint32_t mask = (~((~0) << 11)) << 4;
如果希望进一步获得bit4~bit14中所存放的数值大小,可在完成以上操作以后,再将结果右移4位:
uint32_t value = x >> 4;
在这一步中需要小心前面得到的结果不能是负数。
由于取出某几个连续位中的值的功能在编码中比较常用,可以将该功能写成一个函数/宏供调用:
uint32_t GetBits(uint32_t number, size_t start, size_t count)
{
return (number & ((~((~0) << count)) << start)) >> start;
}
4、用掩码将第m位开始的连续n位的值置0
下面这个例子,是将某输入数字的bit4~bit14的值置为0,其他位保持不变。(注意此例中最低位为bit0,最高位为bit31)
void BitTest4()
{
uint32_t x = 0xF596DF32;
uint32_t mask = 0xFFFF800F;
x = x & mask;
}
该示例中直接硬编码了mask的值。但我们也可以通过一些操作来计算生成掩码:
①使用取反将0置为全1:~0
②左移n位,形成低n位为0,其他位为1的掩码:(~0) << n
③再次取反,形成低n位为1,其他位为0的掩码:~((~0) << n)
④再次左移m位,形成中间需要置0的n位为1,其他位为0的掩码:(~((~0) << n)) << m
⑤再次取反,形成中间需要置0的n位为0,其他位为1的掩码:~((~((~0) << n)) << m)
使用这种方法,示例中的mask可以写成:(请注意在编程环境下数字字面量的宽度是否足够)
uint32_t mask = ~((~((~0) << 11)) << 4);
5、用掩码将部分连续的位置为1
如果需要将某些位置为1而不是0,方法与前面类似,只不过需要指定位为1的掩码,操作是按位或而不是按位与。
例如:将某输入数字的bit4~bit14的值置为1,其他位保持不变。(注意此例中最低位为bit0,最高位为bit31)
void BitTest5()
{
uint32_t x = 0xF596DF32;
uint32_t mask = (~((~0) << 11)) << 4;
x = x | mask;
}
6、将第m位开始的连续n位的值设置成指定的值
如果要将某个值填入到指定的位置中,可以采用类似3.2.5的方法,但是此时的“掩码”不再是全1,而是需要设置的值。
void BitTest6()
{
uint32_t x = 0xF596DF02;
uint32_t value = 5 << 4; // 将5设置到bit4~bit7中
x = x | value; // 结果为0xF596DF52
}
需要注意的是,在用这种方法填值以前,一定要保证目标位置已经是全0,否则结果不正确。
如果目标位置不是全0,则可以先用3.2.4的方式将其清零。
由于该功能较为常用,可以封装成函数/宏,调用时先将目标位置清零,然后填入指定的值:
uint32_t FillZeroBits(uint32_t number, size_t start, size_t count)
{
return number & (~((~((~0) << count)) << start));
}
uint32_t SetBits(uint32_t number, uint32_t value, size_t start, size_t count)
{
uint32_t result = FillZeroBits(number, start, count);
return result | ((value & (~((~0) << count))) << start);
}
在这个示例函数中,还对value值进行了count位的裁剪,以防误输入过大的value导致其他位被意外篡改。