std::bitset 是将十进制整数转二进制字符串最简单稳妥的方式,适合已知位宽场景,自动补前导零,但仅接受无符号类型,负数会模运算转换而非补码。

用 std::bitset 转十进制整数为二进制字符串最简单
直接用 std::bitset 是 C++ 里最稳妥、最不易出错的方式,尤其适合已知位宽(比如 8/16/32 位)的整数。它底层不依赖平台字节序,输出纯二进制字符,且自动补前导零。
注意:std::bitset 构造函数只接受无符号整数类型(unsigned long 或 unsigned long long),传入负数会按模运算转成大正数,不是补码表示——这点容易踩坑。
示例:
int n = 13; std::bitset<8> b(n); // 8位宽度,结果是 "00001101" std::cout << b << "\n"; // 输出 00001101
常见写法:
立即学习“C++免费学习笔记(深入)”;
- 位宽必须是编译期常量,不能写
std::bitset<n></n>(n 是变量) - 若不确定最大值,选足够大的位宽,如
std::bitset覆盖int - 要转成
std::string:用b.to_string();要取某一位:用b[i]
处理负数时别直接塞进 bitset,先转成补码形式
std::bitset 不理解符号位,-1 传进去会变成 UINT_MAX 对应的二进制(比如 bitset(-1) 得到 "11111111",看似对,但这是巧合;bitset(-2) 是 "11111110",也碰巧符合 8 位补码——但这只是因为 unsigned char(-2) 恰好等于补码值。一旦位宽和类型不匹配,结果就不可靠。
安全做法是手动转补码:
int n = -5; std::bitset<8> b(static_cast<unsigned char>(n)); // 强制按 8 位补码解释 // 或更通用: std::bitset<32> b32(*reinterpret_cast<const uint32_t*>(&n));
但后者依赖小端+严格别名规则,不推荐。实际项目中,如需负数二进制展示,建议用条件逻辑分正负,或改用 std::format(C++20)配合位操作。
不用 bitset?手写循环除 2 更灵活但易漏边界
如果位宽不确定、或需要去掉前导零、或输入是任意大小整数(如 long long 甚至大数),bitset 就不够用了。此时用除 2 取余循环更可控。
关键点:
- 必须从低位往高位算,所以结果要反转;空输入(0)要特判
- 用
do-while避免 0 被跳过:do { bits += '0' + (n & 1); n >>= 1; } while (n); - 右移符号数(
int)是实现定义行为,务必先转成无符号类型再移位 - 例如:对
int n = -1,应先转unsigned int u = static_cast<unsigned int>(n)</unsigned>再处理
性能与可读性权衡:bitset 快但死板,to_chars(C++17)不支持二进制
std::bitset 构造和输出都是常数时间,编译期确定位宽还能被优化掉大部分逻辑;而手写循环是 O(log n),但胜在逻辑透明、可定制(比如加空格分隔、每 4 位一组)。
注意:std::to_chars 目前(C++20)只支持十进制、八进制、十六进制,不支持二进制——别白费劲查文档了。
真正需要高性能批量转换时,可预生成 0–255 的二进制字符串查表,再拼接,但日常完全没必要。
多数情况,std::bitset(static_cast<unsigned>(x)).to_string()</unsigned> 就够用;唯一容易被忽略的是:它默认带前导零,而很多人其实想要“自然位宽”(即不带左边多余的 0),这时就得自己截断或换手写逻辑。










