std::bitset 最快最安全但仅适用于编译期已知位宽;它无动态内存、截断风险小、支持 to_string(),但模板参数须为常量表达式,负数按补码处理,超范围会静默截断。

用 std::bitset 最快最安全,但只适用于编译期已知位宽的整数
直接把十进制整数转成二进制字符串显示,std::bitset 是最省心的选择——它不涉及动态内存、无符号截断风险小、输出可直接用 to_string()。
但注意:模板参数必须是常量表达式,比如 std::bitset、std::bitset,不能写 std::bitset<n></n>(n 是变量)。
- 适用于
int、unsigned int等能隐式转换为对应位宽整型的值,超范围会静默截断(如std::bitset(257)得到"00000001") - 负数会被按补码解释(
std::bitset(-1)→"11111111"),不是你想看的“-11111111”这种带符号表示 - 如果只要打印、不存字符串,用
cout (x)更轻量
示例:
int x = 13;<br>std::cout << std::bitset<8>(x) << "n"; // 输出 00001101
手写循环除 2 取余,兼容任意大小和符号,但要自己处理负号和逆序
这是最通用的办法,不依赖模板、不限位宽、能明确控制格式(比如要不要前导零、是否加“0b”前缀、负数怎么表示)。
立即学习 “C++ 免费学习笔记(深入)”;
核心逻辑就三步:取绝对值 → 模 2 记余 → 商整除 2,直到商为 0;最后把余数序列倒过来。
- 不处理负数时,
-5会变成"101"而非"-101",得额外判断原值符号 - 结果是字符串,每次
push_back后要reverse,别忘了 - 输入为 0 时循环不进,必须单独返回
"0",否则结果为空
示例:
std::string dec2bin(int n) {<br> if (n == 0) return "0";<br> bool neg = n < 0;<br> unsigned int u = neg ? -n : n;<br> std::string s;<br> while (u) {<br> s.push_back('0' + (u & 1));<br> u >>= 1;<br> }<br> std::reverse(s.begin(), s.end());<br> return neg ? "-" + s : s;<br>}
std::format(C++20)能一行搞定,但 MSVC 早期版本不支持,Clang 需开启 -std=c++20
如果你用的是较新工具链,std::format("{:b}", x) 是最简洁的方案,自动处理符号、无截断、支持 long long,还能加宽度、填充等格式控制。
但它不是万能的:GCC 12+、Clang 14+、MSVC 19.30+ 才稳定支持;老版本编译直接报错 ‘format’is not a member of‘std’。
-
{:b}对负数输出补码形式(如std::format("{:b}", -1)在 32 位系统上是 32 个 1) - 想输出带符号的十进制风格(如
"-101"),得自己判断符号再拼接,std::format不提供这种模式 - 若需前导零对齐,用
{:08b},但注意这仍按无符号解释被格式化的值
示例:
std::string s = std::format("{:b}", 42); // "101010"
位运算右移 + & 1 比除法快,但要注意有符号右移行为未定义
在循环实现里,用 n & 1 取最低位、n >>= 1 右移,比 n % 2 和 n / 2 更高效,尤其对大数或高频调用场景。
但致命坑在于:对 int 做右移,C++ 标准规定“符号位扩展”行为是实现定义的。GCC/Clang 默认算术右移(负数补 1),但严格来说不能依赖——所以务必先转成无符号类型再操作。
- 别写
int x = -5; while(x) {x >>= 1;}—— 可能死循环 - 正确做法是转
unsigned int或uint32_t,再移位 - 如果原始值可能大于
uint32_t范围(比如long long),得选对应无符号类型,否则高位丢失
真正麻烦的从来不是“怎么转”,而是你没想清楚:这个二进制字符串到底给谁看?调试用、存配置、做位掩码,还是网络协议里发?不同用途,对前导零、符号、位宽、端序的要求天差地别。别急着套函数,先盯住下游怎么消费它。






























