C++ 11和20中的位域使用说明-2
std::bitset
是一个模板类,用于表示和操作固定大小的位序列。它非常适合处理标志、权限、二进制数据等场景
基础知识:
#include <iostream>
#include <bitset>
#include <string>// 模板参数 N 是位集的大小(编译时确定)
std::bitset<N> bitset_name;
示例 1:基本构造与初始化
#include <iostream>
#include <bitset>
#include <string>int main() {// 1. 默认构造:所有位为 0std::bitset<8> b1; // "00000000"std::cout << "b1: " << b1 << std::endl;// 2. 从整数构造 (值被转换为其二进制表示)std::bitset<8> b2(42); // 42 的二进制是 101010, 所以是 "00101010"std::cout << "b2 (from int 42): " << b2 << std::endl;// 3. 从字符串构造std::bitset<8> b3("1010"); // 不足8位,前面补0 -> "00001010"std::cout << "b3 (from string \"1010\"): " << b3 << std::endl;std::bitset<8> b4(std::string("11001100"));std::cout << "b4 (from std::string): " << b4 << std::endl;return 0;
}
输出:
b1: 00000000
b2 (from int 42): 00101010
b3 (from string "1010"): 00001010
b4 (from std::string): 11001100
示例 2:C++20 新增的构造函数 - std::from_chars
这是 C++20 的一个重要改进,允许从字符序列中解析位集,并能报告解析错误。
#include <iostream>
#include <bitset>
#include <charconv> // For std::from_chars
#include <array>int main() {const char* str = "11001";std::bitset<8> b;// 使用 std::from_chars 解析auto [ptr, ec] = std::from_chars(str, str + std::strlen(str), b, 2); // 2 表示二进制基数if (ec == std::errc{}) {std::cout << "Parsed successfully: " << b << std::endl;std::cout << "Stopped at character: '" << *ptr << "'" << std::endl;} else if (ec == std::errc::invalid_argument) {std::cout << "Invalid binary string!" << std::endl;} else if (ec == std::errc::result_out_of_range) {std::cout << "String too long for bitset size!" << std::endl;}// 尝试解析包含非法字符的字符串const char* invalid_str = "110x1";std::bitset<8> b_invalid;auto [ptr2, ec2] = std::from_chars(invalid_str, invalid_str + std::strlen(invalid_str), b_invalid, 2);if (ec2 != std::errc{}) {std::cout << "Parsing failed as expected for '110x1'" << std::endl;}return 0;
}
输出:
Parsed successfully: 00011001
Stopped at character: ''
Parsing failed as expected for '110x1'
说明:
std::from_chars
提供了更安全、更高效的解析方式。- 它返回一个
std::from_chars_result
,包含一个指向停止解析位置的指针ptr
和一个错误码ec
。 - 这使得你可以精确地知道解析是否成功以及在哪里停止。
示例 3:常用操作方法
#include <iostream>
#include <bitset>int main() {std::bitset<8> b("10101010");std::cout << "Original: " << b << std::endl;// 1. 访问单个位std::cout << "Bit at pos 0: " << b[0] << std::endl; // 最右边是低位 (pos 0)std::cout << "Bit at pos 7: " << b[7] << std::endl; // 最左边是高位 (pos 7)// 2. 修改单个位b[1] = 1; // Set bit 1 to 1b.set(3); // Set bit 3 to 1b.reset(5); // Set bit 5 to 0b.flip(7); // Toggle bit 7std::cout << "After modifications: " << b << std::endl;// 3. 批量操作b.set(); // Set all bits to 1std::cout << "All set: " << b << std::endl;b.reset(); // Set all bits to 0std::cout << "All reset: " << b << std::endl;b.flip(); // Flip all bits (now all 1s)std::cout << "All flipped: " << b << std::endl;// 4. 查询std::cout << "Count of 1s: " << b.count() << std::endl; // 应该是 8std::cout << "Size: " << b.size() << std::endl; // 8std::cout << "All bits are 1? " << b.all() << std::endl; // truestd::cout << "Any bit is 1? " << b.any() << std::endl; // truestd::cout << "No bit is 1? " << b.none() << std::endl; // falsereturn 0;
}
输出:
Original: 10101010
Bit at pos 0: 0
Bit at pos 7: 1
After modifications: 00101111
All set: 11111111
All reset: 00000000
All flipped: 11111111
Count of 1s: 8
Size: 8
All bits are 1? 1
Any bit is 1? 1
No bit is 1? 0
示例 4:位运算
std::bitset
支持标准的位运算符。
#include <iostream>
#include <bitset>int main() {std::bitset<8> a("11001100");std::bitset<8> b("10101010");std::cout << "a: " << a << std::endl;std::cout << "b: " << b << std::endl;// 位与std::cout << "a & b: " << (a & b) << std::endl; // 10001000// 位或std::cout << "a | b: " << (a | b) << std::endl; // 11101110// 位异或std::cout << "a ^ b: " << (a ^ b) << std::endl; // 01100110// 位非std::cout << "~a: " << (~a) << std::endl; // 00110011// 左移/右移std::cout << "a << 2: " << (a << 2) << std::endl; // 00110000 (左移2位,低位补0)std::cout << "a >> 2: " << (a >> 2) << std::endl; // 00110011 (右移2位,高位补0)return 0;
}
输出:
a: 11001100
b: 10101010
a & b: 10001000
a | b: 11101110
a ^ b: 01100110
~a: 00110011
a << 2: 00110000
a >> 2: 00110011
示例 5:转换为其他类型
#include <iostream>
#include <bitset>int main() {std::bitset<8> b("10101010"); // 十进制是 170// 转换为 unsigned longunsigned long ul = b.to_ulong();std::cout << "to_ulong(): " << ul << std::endl; // 170// 转换为 unsigned long long (C++11 起)unsigned long long ull = b.to_ullong();std::cout << "to_ullong(): " << ull << std::endl; // 170// 转换为字符串std::string str = b.to_string();std::cout << "to_string(): " << str << std::endl; // "10101010"// 注意:如果位集的值超出了目标类型的范围,to_ulong/to_ullong 会抛出 std::overflow_errortry {std::bitset<64> huge_b;huge_b.set(); // All bits set to 1, value is 2^64 - 1unsigned long bad_ul = huge_b.to_ulong(); // This will throw!} catch (const std::overflow_error& e) {std::cout << "Overflow caught: " << e.what() << std::endl;}return 0;
}
输出:
to_ulong(): 170
to_ullong(): 170
to_string(): 10101010
Overflow caught: bitset::to_ulong
总结
std::bitset
是处理固定长度二进制数据的绝佳选择。C++20 通过引入 std::from_chars
构造支持,极大地增强了其解析能力和错误处理机制,使其在需要从文本输入构建位集的场景下更加健壮和高效。
主要优点:
- 类型安全: 避免了原始指针和位操作的错误。
- 可读性强: 代码意图清晰。
- 功能丰富: 提供了丰富的成员函数进行位操作、查询和转换。
- 性能良好: 通常由编译器优化为高效的机器指令。
适用场景:
- 状态标志管理
- 权限控制
- 布隆过滤器 (Bloom Filter) 的底层实现
- 二进制协议解析
- 任何需要紧凑存储布尔值集合的地方