Cpp学习9 第 O 章 位运算
O.1 — 通过 std::bitset 进行位标志和位操作
在某些存储密集型场景下,为了提高存储效率,将 8 个独立的布尔值“打包”到一个字节中可能很有用。要实现这些功能,我们需要能够在位级别操作对象。
C++ 为我们提供了实现这一目标的工具。修改对象中的单个位称为位操作 。
Bit flags 位标志
我们不必将对象视为包含单个值,而是可以将对象中的每一位都视为一个独立的布尔值。当对象的各个位用作布尔值时,这些位被称为位标志 。
要定义一组位标志,我们通常会使用适当大小的无符号整数(8 位、16 位、32 位等,具体取决于我们有多少个标志),或者 std::bitset
1 |
|
位操作是少数几个应该明确使用无符号整数(或 std::bitset )的情况之一。
给定一个比特序列,我们通常从右到左对比特进行编号,从 0 开始(而不是 1)。每个数字表示一个比特位置 。
76543210 Bit position
00000101 Bit sequence
通过 std::bitset操作位
std::bitset 提供了 4 个关键成员函数,可用于进行位操作:
- test() 函数允许我们查询一个比特是 0 还是 1。
- set() 允许我们打开一个位(如果该位已经打开,则此操作不会执行任何操作)。
- reset() 允许我们关闭一个位(如果该位已经关闭,则此操作不会执行任何操作)。
- flip() 函数允许我们将一个位值从 0 翻转为 1,反之亦然。
这些函数都以我们要操作的 位的位置 作为它们的唯一参数。
1 |
|
给代码片段命名可以提高代码的可读性:
1 |
|
在之后的课程里会展示 枚举器 如何创建更好的命名位集合。
std::bitset 的大小通常是存储这些位所需的字节数, 向上 取整到最接近的 sizeof(size_t) ,在 32 位机器上为 4 字节,在 64 位机器上为 8 字节。
查询 std::bitset
- size() 返回位集中的位数。
- count() 返回位集中设置为
true位数。 - all() 返回一个布尔值,指示是否所有位都设置为
true。 - any() 返回一个布尔值,指示是否有任何位设置为
true。 - none() 返回一个布尔值,指示是否没有位设置为
true。
1 |
|
O.2 — 位运算符
左移<< 右移>> 按位非~ 按位与& 按位| 按位异或^
0011 << 1 is 0110
0011 << 2 is 1100
0011 << 3 is 1000
1100 />/> 1 is 0110
1100 />/> 2 is 0011
1100 />/> 3 is 0001
运算符能够根据参数的类型改变其行为,这种能力利用了_运算符重载_ 这一特性
~0011 is 1100
~0000 0100 is 1111 1011
按位赋值运算符
<<= >>= &= |= ^=
位运算符会将具有较窄整数类型的操作数提升为 int 或 unsigned int 。operator~ 和 operator<< 对位宽敏感,根据操作数的宽度不同,可能会产生不同的结果。为了确保结果正确,在使用此类位运算之前,请先将结果 static_cast 回较窄的整数类型。
尽可能避免对小于 int 的整数类型进行位移操作。
O.3 — 使用位运算符和位掩码进行位操作
Bit masks 位掩码
位掩码是一组预定义的位,用于选择后续操作将修改哪些特定位。
C++14 支持二进制字面量,因此定义这些位掩码很容易:
1 |
|
为位掩码赋予有意义的名称,以便记录位标志的含义。
对于大多数程序而言,使用位标志节省的内存量不足以弥补增加的复杂性。但对于包含成千上万甚至数百万个相似对象的程序来说,使用位标志可以显著降低内存占用。如果需要,这是一种值得掌握的优化技巧。
O.4 — 二进制和十进制表示之间的整数转换
有符号整数通常使用二进制补码法存储。在二进制补码法中,最左边(最高有效位)的位用作符号位。符号位为 0 表示该数为正数(或零),符号位为 1 表示该数为负数。
负有符号数用二进制表示为正数的按位取倒数,再加 1。
(哪来的计算机组成课程知识?)
- 标题: Cpp学习9 第 O 章 位运算
- 作者: 铁名_IronName
- 创建于 : 2026-08-08 14:49:05
- 更新于 : 2026-08-08 15:32:40
- 链接: https://blog.ironname.top/2026/Cpp/Cpp学习9/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。