std::bitset 初始化不可直接用整数赋值,需用字符串如"1111011"或显式ull后缀整数如123ull;size()返回编译期模板参数n,非有效位数。

bitset 初始化时别直接用整数赋值
很多人写 std::bitset b = 123;,以为能自动转成二进制位,结果编译失败——std::bitset 的构造函数不接受裸整数(除 unsigned long long 且需显式类型匹配)。它只支持字符串、unsigned long 或 unsigned long long,且后者会按数值的二进制表示填充(高位补零),不是你想的“把 123 当作位模式”。
正确做法是:
- 用字符串初始化:
std::bitset b("1111011");(注意:字符串长度不能超模板参数,且只能含 '0'/'1') - 用整数初始化(推荐):
std::bitset b(123ULL);,此时等价于二进制01111011(8 位,低位对齐) - 若想按位掩码语义赋值(比如第 0、1、6 位为 1),别硬算数值,改用
set():b.set(0).set(1).set(6);
bitset 的 size() 是编译期常量,别 runtime 查长度
std::bitset<n>::size()</n> 返回的是模板参数 N,不是实际“用了多少位”。它在编译期就确定,不能像 std::vector 那样动态增长或查询有效位数。有人误以为 b.size() 能告诉你“当前有多少个 1”,其实完全不是。
常见误用场景:
立即学习“C++免费学习笔记(深入)”;
- 循环遍历所有位时写
for (int i = 0; i —— 这是对的,但前提是你要的就是全部 <code>N位 - 想统计 1 的个数却调
b.size()—— 应该用b.count() - 想判断是否“全空”却用
b.size() == 0—— 永远 false;应该用b.none()或b == 0
位运算符重载行为和内置类型一致,但注意左移右移的边界
std::bitset 重载了 &、|、^、~、、<code>>>,语义和内置整数一致,但移位操作有关键区别:超出位宽的部分直接丢弃,不会溢出或报错。
比如:
std::bitset<4> a("1011");
a <<= 2; // 结果是 "1100",原高位 "10" 被移出,低位补 0
a >>= 5; // 结果是 "0000",右移超过 4 位,全清零
容易踩的坑:
- 移位后没检查是否全零,导致后续逻辑误判
- 用
模拟乘法时忽略截断(<code>bitset(1) 得到 0,不是 1024) - 和
int混用做运算前没显式转换,引发隐式类型错误(bitset & int不合法)
和 vector、原生整数比,什么时候该用 bitset
std::bitset 是固定大小、栈分配、编译期确定容量的位容器。它快、无堆开销、支持全部位运算符,但不可变长。
选它的典型场景:
- 状态标志集合(如权限掩码、配置开关),总数已知且 ≤ 数百位
- 需要频繁做与/或/异或/翻转等批量位运算,且尺寸固定
- 做位图索引(如筛法中记录质数)、哈希布隆过滤器底层存储(小规模)
别用它的场景:
- 位数不确定或可能很大(如 > 10⁶),改用
std::vector<bool></bool>或手动分块uint64_t[] - 要频繁 push/pop 单个位,
bitset没 push 接口,得自己算下标 - 需要跨平台序列化——
to_string()或to_ulong()可能因大小端或位序歧义出错,务必测试目标平台
最常被忽略的一点:bitset 的 operator[] 下标 0 是最低位(LSB),和多数硬件/协议约定一致,但和字符串初始化顺序相反("101" 表示 bit2=1, bit1=0, bit0=1)。这点一旦搞反,调试半天都看不出哪错了。








