std::hex 是作用于整个输出流的持久性操纵符,会持续将后续整数转为小写十六进制且无前缀,需用 std::dec 等显式恢复。

用 std::hex 和 std::cout 输出整数的十六进制形式
直接用 std::hex 会把后续所有整数输出都切为十六进制,且不带前缀(比如没有 0x),也不控制大小写或补零。它只是个流操纵符,作用于整个输出流,不是一次性的格式修饰。
常见错误是以为写了 std::hex 就只影响下一项——其实它会持续生效,直到被另一个进制操纵符(如 std::dec)覆盖:
int a = 255, b = 16; std::cout << std::hex << a << " " << b << std::endl; // 输出:ff 10 std::cout << a << std::endl; // 仍是 ff(因为 hex 还在生效)
- 必须手动恢复:加
std::dec回到十进制,或用std::ios_base::fmtflags保存/恢复状态 -
std::hex只对整型有效(int、long、unsigned short等),对float或double无效,也不会报错,而是按默认浮点格式输出 - 输出字母默认小写(
a-f),想大写需配合std::uppercase
加 0x 前缀和补零要用 std::showbase 和 std::setfill/std::setw
std::showbase 让 std::hex 自动加 0x(对 std::oct 加 0,std::dec 无效果),但它不控制宽度;补零得靠 std::setfill('0') + std::setw(n),而且 setw 只对**下一个输出项**生效:
#includeint x = 15; std::cout << std::hex << std::showbase << std::setfill('0') << std::setw(4) << x << std::endl; // 输出:0x000f
-
std::setw不会保留,每次都要重设;漏写就变成不补零 -
std::setfill是持久的,设一次会影响后续所有需要填充的输出(比如之后再用setw输出字符串,也会用'0'填充) - 如果只想临时补零,建议用
std::format(C++20)或sprintf避免状态污染
C++20 推荐用 std::format 替代流操纵符做十六进制格式化
std::format 是无状态、一次性的,语义清晰,不易出错,支持前缀、大小写、宽度、对齐等全部控制,且类型安全:
立即学习“C++免费学习笔记(深入)”;
#includeint v = 255; std::string s1 = std::format("{:#x}", v); // "0xff" std::string s2 = std::format("{:04x}", v); // "00ff" std::string s3 = std::format("{:#06X}", v); // "0X00FF"
-
{:#x}→ 带0x前缀;{:04x}→ 宽度 4、左补零、小写;X表示大写 - 不依赖流状态,不会影响其他输出;也没有
std::hex的“传染性”问题 - 注意:GCC 13+、Clang 15+、MSVC 19.30+ 才完整支持;老编译器需用
fmt库替代
输出指针地址时别误用 std::hex
直接对指针用 std::hex 会导致未定义行为或编译失败(尤其开启严格检查时)。正确做法是先转成 uintptr_t,再格式化:
int val = 42; int* p = &val; std::cout << std::hex << reinterpret_cast(p) << std::endl; // OK // 错误写法:std::cout << std::hex << p << std::endl; // 不可移植,可能崩溃
- 指针输出应统一用
%p配合printf,或 C++20 的std::format("{:p}", p) -
std::hex对指针无标准语义,不同平台输出可能截断、乱码甚至 crash - 即使编译通过,也可能在 64 位系统上只输出低 32 位地址
十六进制输出最易踩的坑不是语法写错,而是流状态残留和指针误用——前者让后续输出莫名其妙变进制,后者在不同平台表现不一,调试起来特别隐蔽。










