内存的位运算
示例:提取和设置标志位
假设我们有一个32位的整数,其中不同的位代表不同的标志。例如:
-
位0:是否开启日志(0表示关闭,1表示开启)
-
位1:是否启用调试模式(0表示禁用,1表示启用)
-
位2-31:保留或用于其他目的
提取标志位
如果我们想要检查是否启用了调试模式(位1),可以使用以下代码:
int flags = getStatusFlags(); // 假设这是一个获取状态标志的函数
bool isDebugModeEnabled = (flags & (1 << 1)) != 0;
这里的操作解释如下:
-
(1 << 1)
:将1左移1位,得到00000010
(二进制)。 -
flags & (1 << 1)
:对flags
和00000010
进行按位与运算,结果中只有位1会被保留,其他位都会被清零。 -
!= 0
:检查结果是否不为0,以确定是否启用了调试模式。
设置标志位
如果我们想要启用调试模式,可以使用以下代码:
int flags = getStatusFlags(); // 获取当前状态标志
flags |= (1 << 1); // 启用调试模式
setStatusFlags(flags); // 假设这是一个设置状态标志的函数
这里的操作解释如下:
-
(1 << 1)
:将1左移1位,得到00000010
(二进制)。 -
flags |= (1 << 1)
:对flags
和00000010
进行按位或运算,结果中位1会被设置为1,其他位保持不变。
扩展:其他位运算的应用
1. 清除特定位
如果我们想要清除调试模式标志(位1),可以使用以下代码:
int flags = getStatusFlags(); // 获取当前状态标志
flags &= ~(1 << 1); // 清除调试模式标志
setStatusFlags(flags); // 设置状态标志
这里的操作解释如下:
-
~(1 << 1)
:对00000010
进行按位取反,得到11111111 11111111 11111111 11111101
(二进制)。 -
flags &= ~(1 << 1)
:对flags
和取反后的结果进行按位与运算,结果中位1会被清零,其他位保持不变。
2. 切换特定位
如果我们想要切换调试模式标志(位1),可以使用以下代码:
int flags = getStatusFlags(); // 获取当前状态标志
flags ^= (1 << 1); // 切换调试模式标志
setStatusFlags(flags); // 设置状态标志
这里的操作解释如下:
-
(1 << 1)
:将1左移1位,得到00000010
(二进制)。 -
flags ^= (1 << 1)
:对flags
和00000010
进行按位异或运算,结果中位1会被切换(如果原来是0则变为1,如果原来是1则变为0),其他位保持不变。
3. 检查多个标志
如果我们想要同时检查是否启用了日志和调试模式,可以使用以下代码:
int flags = getStatusFlags(); // 获取当前状态标志
bool isLogEnabled = (flags & (1 << 0)) != 0;
bool isDebugModeEnabled = (flags & (1 << 1)) != 0;
这里的操作解释如下:
-
(flags & (1 << 0)) != 0
:检查位0是否被设置,以确定是否启用了日志。 -
(flags & (1 << 1)) != 0
:检查位1是否被设置,以确定是否启用了调试模式。
通过这些示例,我们可以看到位运算在处理标志位时的高效性和灵活性。它们可以直接在二进制级别上操作数据,避免了额外的计算或转换步骤,非常适合在需要高效处理大量数据的场景中使用。
总之别被束缚:
像 int length = (0x11112222 >> 16) & 0FFFF; 它的结果就是length == 0x1111; 它的意思就是把高位16位二进制(高位的两个字节)移动到低16位,进行与运算。