std::hex只改变进制,不控制宽度和填充,因此单字节输出连在一起;需配合std::setfill('0')和std::setw(2)且每次输出前重置,因流状态累积、setw仅对下一项生效。

用 std::hex 和 std::setw 格式化单字节输出时为什么总连在一起?
因为默认不补零、不加空格、不换行,std::hex 只改进制,不控制宽度和填充。必须显式设置:std::setfill('0')、std::setw(2),且每次输出单字节都要重置(流状态是累积的)。
常见错误写法:os → 输出可能是 <code>a 而非 0a,后续字节还会受前面 std::hex 影响,导致整数输出也变十六进制。
- 每字节前加空格(首字节除外)
- 强制两位宽、左补零:
std::setw(2) - 避免流状态污染:要么用临时
std::ostringstream,要么每次手动恢复十进制(std::dec)
如何按 16 字节一行 + 地址前缀 + ASCII 预览生成缩进 Hex Dump?
标准库没有现成函数,得自己拼。关键结构是三段:地址列(如 00000000:)、十六进制数据区(16组 xx )、ASCII 列(不可见字符转 .)。
注意点:
- 地址用
std::hex+std::setw(8)+std::setfill('0'),输出后加:和空格 - 每行最多处理 16 字节;不足时 hex 区补
" "(三个空格),ASCII 区补空格 - ASCII 列每个字节判断:
isprint(byte) ? byte : '.',但必须先转为unsigned char再判,否则负值会崩
示例核心逻辑片段:
std::ostringstream oss;
for (size_t i = 0; i <h3>为什么直接用 <code>sprintf</code> 或 <code>std::format</code>(C++20)更干净?</h3><p><code>sprintf</code> 避免流状态干扰,<code>std::format</code> 更安全且表达力强——但它在 GCC 13/Clang 15 前支持不全,MSVC 2019 Update 16.10+ 才稳定。</p><p>用 <code>std::format</code> 的典型写法:</p><pre class="brush:php;toolbar:false;">
auto line = std::format("{:08x}: {:02x} {:02x} ... |{:c}{:c}...|",
offset,
static_cast<unsigned>(buf[0]), static_cast<unsigned>(buf[1]),
// ...
isprint(buf[0]) ? buf[0] : '.', isprint(buf[1]) ? buf[1] : '.'
);
</unsigned></unsigned>
-
{:02x}自动补零、两位宽,比流操作符简洁 - 每个字节必须转
unsigned再传入,否则char有符号扩展会导致高位全是 f - ASCII 列仍需手动
isprint判断,std::format不做字符过滤
遇到中文路径或含 \0 的 Buffer 怎么办?
Hex dump 本质是字节序列可视化,跟编码无关。所谓“中文路径”只是文件名字符串的编码问题,dump 的是文件内容 buffer,只要读取正确(如用 std::ifstream 以 std::ios::binary 打开),就完全不影响。
真正要注意的是:\0 是合法字节,不是字符串结束符。别用 strlen 算 buffer 长度,必须由调用方明确传入 size_t len。
- 误用
strlen(reinterpret_cast<const char>(buf))</const>→ 遇到第一个\0就截断 - 正确做法:dump 函数签名必须含长度参数,例如
std::string hex_dump(const void* buf, size_t len) - 如果 buffer 来自
std::vector<uint8_t></uint8_t>,直接用.data()和.size()
缩进和可读性靠格式控制,和内容是否含 \0 完全无关。容易被忽略的是:哪怕只 dump 1 字节,也要保证地址列、hex 区、ascii 列对齐——否则多行拼起来会错位。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











