std::hex 对 char 类型无效,因其按字符而非数值输出;需强制转换为 unsigned int 或 int 才能以十六进制显示字节值。

用 std::hex 和 std::uppercase 输出文件内容时,为什么全是乱码或不显示?
因为 std::hex 只影响整数输出格式,对 char 类型默认按字符(而非数值)打印。读出来一个字节是 'A'(ASCII 65),直接 cout 输出的就是字母 A,不是 <code>41。
- 必须把每个
char强转为无符号整数类型,比如static_cast<unsigned char>(c)</unsigned>,否则负值(如\xFF)会扩展成大负数再转十六进制,结果错乱 -
std::uppercase确实能让a~f变成A~F,但它只对当前流生效,且需配合std::hex使用 - 别忘了用
std::setw(2) 补零,否则 <code>0xA会输出成A,不是标准两位十六进制
std::ifstream 读二进制文件必须加 std::ios::binary 吗?
必须加。Windows 下不加会导致 \r\n 被悄悄转成 \n,文件长度变短、数据错位;Linux/macOS 虽然影响小,但跨平台代码必须统一处理。
- 打开时写成
std::ifstream f("a.bin", std::ios::binary) - 读取用
f.get()或f.read()都可以,但前者每次只读一个字节,适合逐字节格式化;后者适合批量读入缓冲区再处理 - 用
f.peek() == EOF判断结尾比!f更可靠,尤其在读到末尾时流状态可能还没置位
怎么避免每行输出太多字节导致难以阅读?
十六进制 dump 通常按 16 字节/行组织,左侧加偏移地址,右侧附 ASCII 可视化——这不是格式化开关能解决的,得手写排版逻辑。
- 每读 16 字节就换一行,用
std::hex 打印起始地址(offset 每次 += 16) - 每个字节输出前先
std::hex (b) - ASCII 区域:非控制字符(
isprint(b))直接输出,否则用.占位 - 注意:
std::setfill是持久的,每轮循环开头要重设,否则后续数字可能被填满
完整可运行示例(带地址+双列+大写)
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cctype>
<p>int main(int argc, char* argv[]) {
if (argc != 2) return 1;
std::ifstream f(argv[1], std::ios::binary);
if (!f) { std::cerr << "open failed\n"; return 1; }</p><pre class='brush:php;toolbar:false;'>int offset = 0;
const int width = 16;
while (f) {
// 地址列
std::cout << std::hex << std::setw(8) << std::setfill('0') << offset << " ";
// 十六进制列
for (int i = 0; i < width && f; ++i) {
unsigned char b = f.get();
if (f) {
std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<int>(b) << " ";
} else {
std::cout << " ";
}
}
// ASCII 列
std::cout << " |";
f.clear(); f.seekg(offset, std::ios::beg); // 重新定位读指针
for (int i = 0; i < width && f; ++i) {
unsigned char b = f.get();
if (f) {
std::cout << (std::isprint(b) ? static_cast<char>(b) : '.');
}
}
std::cout << "|\n";
offset += width;
f.clear(); f.seekg(offset, std::ios::beg);
}}
立即学习“C++免费学习笔记(深入)”;
实际使用时注意:上面示例里用了两次 seekg 回溯读取,是为了同时输出 hex 和 ASCII 列。如果只输出十六进制,不需要回溯,性能更好。真正高频场景(比如分析 GB 级日志)应该用 read(buf, size) 批量读,避免单字节 I/O 开销——这点容易被忽略,但一卡就是几秒。



















