c++位运算运用之位掩码(BitMask)
场景:假如我想写一个动画小人,某个接口仅仅传int型就可以同时控制小人抬右手、抬左脚、闭眼睛,或者同时抬右手,抬左脚、睁眼睛。这儿其实就是一些动作的组合,可以把不同动作对应到int的每一个位上,int 占4个字节,每个字节8位,共32位,每一个位来表示一种动作,那么可以同时组合32个动作。
内存分布就像这样:
11111111 11111111 11111111 11111111
这样一个int 的值就是INT_MAX
实现:
1.定义枚举表示各种动作:
enum Animation {
None = 0, // 0x0
ShutEye = 1 << 1, // 0x1
OpenEye = 1 << 2, // 0x10
RaiseRightLeg = 1 << 3, // 0x100
RaiseLeftLeg = 1 << 4, // 0x1000
RaiseRightHand = 1 << 5, // 0x10000
raiseLeftHand =1 << 6 // 0x100000
};
1.定义方法实现不同动作组合:
void Dance(int animation)
{
switch (animation)
{
case (ShutEye | RaiseLeftLeg | RaiseRightHand):
std::cout << "小人 举右手 、 抬左腿、 闭眼" << std::endl;
break;
case (OpenEye | RaiseLeftLeg | RaiseRightHand):
std::cout << "小人 举右手 、 抬左腿、 睁眼" << std::endl;
break;
default:
break;
}
}
int main()
{
Dance(ShutEye | RaiseLeftLeg | RaiseRightHand);
std::cout << "Hello World!\n";
}
哈哈哈,脑补一下画面就好,为了说明问题就使用简单的文字说明,如果真得有人个小人在画面上起舞,那将输出行换成相应的实现逻辑即可。
掩码的常用操作:
1.组合不同的标志位,直接使用位运算或(|)起来,就如我想让小人抬左脚和抬右脚 :
RaiseLeftLeg | RaiseRightLeg
2.去掉flag中的某一项,就比如我们永远都不想让小人抬起右脚。这时可以分两步走,第一步把要去掉的标志位取反。第二步在和目标标志位与(&)起来。
那么现在我只想小人的眼睛永远是睁开的,闭着就不美了,怎么办呢? 只需去掉标志ShutEye即可
void Dance(int animation)
{
int noShutEye = ~Animation::ShutEye; // 1. 取反
animation = animation & noShutEye; // 2. 与目标值&起来
// 将上面合并为一行
// animation = animation & (~Animation::ShutEye);
switch (animation)
{
case (ShutEye | RaiseLeftLeg | RaiseRightHand):
std::cout << "小人 举右手 、 抬左腿、 闭眼" << std::endl;
break;
case (OpenEye | RaiseLeftLeg | RaiseRightHand):
std::cout << "小人 举右手 、 抬左腿、 睁眼" << std::endl;
break;
default:
break;
}
}
总结:
位掩码在编码中还是比较常见的,其中要注意的一点就是一个int 仅仅可以表示32种标志,因为只有32位二进制,并且用1标识哪一个位代表什么flag。如果还需要多余32中可以挑一个更大的类型,或者直接使用自定义类,实现与或取反(& | ~)三种操作符,那么即可扩展到好多标志。还有就是去掉标志位时,一定要先取反在与。得呢,今也差不多了,早早就起来撸文章,搞得睡眼朦胧的呢,这可爱的床,我来了。