C++ 中的位运算:如何设置、清除和切换单个位(并保持头脑清醒)
你好,同行!如果你曾经看过别人写的 C++ 代码,看到过像 |、& 和 ~ 这样奇怪的符号,然后问自己“他们为什么要这样做?”——那你来对地方了。今天我们将剖析编程中最流行(而且说实话,也是最优雅)的主题之一:位运算。具体来说,就是如何设置、清除和切换单个位。
这不仅仅是一个学术练习。位操作是一种超能力,你会在很多地方用到它:从处理配置标志和微控制器外设,到优化游戏或数据库中的数据存储。在 Stack Overflow 上,这个问题获得了数十万次浏览——说明它真的很重要。
我们不要枯燥的理论——直接进入正题。开始吧!
我们为什么要处理位?
假设你有 8 个不同的设置(例如,开启声音、显示提示、开启夜间模式等)。你可以将它们存储在八个单独的 bool 类型变量中。但这需要 8 个字节(甚至更多)。而你可以使用一个字节——8 个位,每个位负责一个设置。内存节省了 8 倍——而这仅仅是个开始。
位运算是一种底层魔法,运行速度极快。处理器在一个时钟周期内就能完成它们。对于嵌入式系统、驱动程序和高负载应用程序来说,这一点至关重要。
在 C++ 中,处理位主要使用三个运算符:
|(按位或)——用于设置位。&(按位与)——用于清除位。^(按位异或,XOR)——用于切换位。
还有一个有用的运算符——~(按位非),它翻转所有位。我们在清除位时会用到它。
位编号:我们先约定好
在编程中,位通常从零开始编号。最低有效位 (LSB) 是位 0。最高有效位 (MSB) 对于字节是位 7,对于字(16 位)是位 15,以此类推。
在本文中,为了清晰起见,我们将使用 uint8_t(8 位无符号整数)。但所有示例同样适用于 int、unsigned int、uint32_t 以及任何其他整数类型。
如何设置位 (Set bit)
设置位意味着将其变为 1,无论它之前是什么值。
最简单的方法是使用按位或和一个掩码。掩码是一个数字,其中只有我们想要更改的那个位被设置。
公式:
number |= (1 << bit_number);逐步分解:
1 << bit_number——将 1 左移所需的位置数。如果位号 = 3,那么1 << 3得到二进制00001000。number | mask——或运算会将位设置为 1(如果它原来是 0),如果它已经是 1 则保持为 1。
C++ 代码示例:
#include <iostream>#include <cstdint>
int main() { uint8_t flags = 0b00000000; // 最初所有位都被清除
// 设置第 3 位(从零开始计数) flags |= (1 << 3);
// 现在 flags = 0b00001000 std::cout << "设置第 3 位后: " << static_cast<int>(flags) << std::endl;
// 设置第 0 位 flags |= (1 << 0); // flags = 0b00001001 std::cout << "设置第 0 位后: " << static_cast<int>