std::hex仅设置十六进制格式,不控制宽度和填充;需配合std::setw(2)和std::setfill('0')确保每位字节输出两位十六进制,且须将unsigned char转为int再输出。

std::hex 输出字节流时为什么只改了数字进制,不控制宽度和填充?
因为 std::hex 仅设置整数输出为十六进制格式,它**不改变字段宽度或填充字符**。单独用 std::hex 输出 unsigned char 或 int 时,0 不会显示为 00,10 会变成 a 而非 0a——这在字节流序列化中几乎总是错的。
必须配合 std::setw 和 std::setfill 才能保证每个字节稳定输出两位十六进制字符。
-
std::setw(2)设置最小字段宽度为 2(注意:它只对下一个输出项生效,不可复用) -
std::setfill('0')设定填充字符为'0',且该设置会持续生效直到再次修改 - 务必把
unsigned char先转成int再输出,否则可能被当 ASCII 字符打印(如0x0a变成换行符)
写二进制字节流到文件时,别用
如果你本意是把内存里一串 unsigned char 数据原样写入文件(比如导出 PNG header),就**不该用 operator 配合 <code>std::hex**——那输出的是可读的十六进制文本,不是原始字节。
真正“输出字节流”分两种场景:
-
导出为十六进制文本文件(如 dump.txt):用
std::ofstream++ <code>std::hex+std::setw -
导出为原始二进制文件(如 image.bin):用
std::ofstream::write(),完全绕过格式化
混淆这两者会导致文件大小膨胀 2–4 倍(每个字节变 2–4 字符),且无法被二进制工具识别。
std::hex + setfill 的典型安全写法(文本 hex dump)
以下代码把 std::vector<unsigned char></unsigned> 每个字节转成两位小写十六进制、空格分隔,写入文本文件:
std::ofstream f("dump.txt");
f 0) f (data[i]);
}
f.close();
关键点:
-
static_cast<int>(data[i])</int>防止符号扩展(尤其当char为 signed 且值 > 0x7f 时) -
std::setw(2)必须在每次前调用,不能只设一次 - 若要大写十六进制,加
std::uppercase;要固定小写,加std::nouppercase(默认小写) - 不要用
std::ios::hex成员函数混搭流操纵符,易覆盖状态
二进制写入更高效,但别误用 hex 格式化逻辑
如果目标是生成真实字节文件(比如加密密钥、网络包 payload),直接用:
std::ofstream f("payload.bin", std::ios::binary);
f.write(reinterpret_cast<const char>(data.data()), data.size());
f.close();
</const>
此时 std::hex、std::setfill 完全无关——它们只影响文本格式化输出。试图对二进制流用这些操纵符,要么无效,要么引发未定义行为(例如 write() 不吃流格式状态)。
容易忽略的是:打开文件时漏掉 std::ios::binary 标志,在 Windows 上会导致 0x0d 0x0a 被悄悄转成单个 0x0a,破坏原始字节一致性。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











