输出十进制整数必须用%d,%i虽在部分环境可用但非标准且行为不一致;类型须严格匹配,如long用%ld、unsigned用%u,否则引发未定义行为。

用 printf 输出 int 要加 %d,不是 %i 或其他
虽然 %i 在大多数实现里也能工作,但 C++ 标准没保证它和 %d 完全等价——尤其在某些嵌入式 libc 或旧编译器上,%i 可能尝试按八进制/十六进制解析输入,而输出时行为不一致。坚持用 %d 是最安全的选择。
常见错误现象:printf("x = %i", x); 看起来正常,但换到 ARM Cortex-M + newlib 环境就可能输出乱码或截断;或者和 scanf("%i", &x) 混用时产生误解。
- 输出十进制整数,只用
%d - 如果要补零、指定宽度(比如日志对齐),写成
%04d或%5d,别漏掉数字前的% - 传参类型必须严格匹配:传
int就用%d;传long得用%ld,否则在 64 位系统上可能只读低 32 位,输出错误值
printf 的参数类型不匹配会直接导致未定义行为
比如把 unsigned int 当 int 传给 %d,或者把 short 直接传进去——C++ 不做隐式类型检查,运行时可能崩,也可能输出负数(高位被解释为符号位)。
典型场景:从硬件寄存器读回一个 uint16_t status,顺手写了 printf("status: %d", status)。表面输出正常,但若该值 > 32767,就变成负数。
立即学习“C++免费学习笔记(深入)”;
- 用
%u输出unsigned int,%hu输出unsigned short - 不确定类型时,显式强转:
printf("val: %d", (int)my_int32)(前提是你知道它真能安全转) - 现代编译器如 GCC/Clang 开
-Wformat(默认开启)能报这类错,别关它
C++ 里混用 printf 和 iostream 可能引发缓冲区不同步
如果你在同一个程序里既用 printf("hello"),又用 std::cout ,且没手动同步,输出顺序可能错乱,尤其重定向到文件时。
原因:printf 走 C stdio 缓冲(stdout),std::cout 走 C++ stream 缓冲,默认各自独立刷新。
- 临时解决:在混用前后加
fflush(stdout)或std::cout.flush() - 长期建议:项目里统一风格——要么全用
printf(适合嵌入式、日志库、性能敏感路径),要么全用std::format(C++20)或std::cout - 注意:
std::ios_base::sync_with_stdio(false)会禁用同步,此时再混用就完全不可预测
替代方案:C++20 的 std::format 更安全但还没普及
std::format("x = {}", x) 类型安全、无需格式符、自动推导,但 MSVC 2022 17.5+、GCC 13、Clang 15 才稳定支持。很多项目还在用 C++17 或更早标准。
如果你不能升级标准,又嫌 printf 太容易出错,可以封装一层:
template<typename T>
void safe_print_int(const char* fmt, T val) {
static_assert(std::is_integral_v<T>, "only integral types allowed");
if constexpr (std::is_signed_v<T>) {
printf(fmt, static_cast<int>(val));
} else {
printf(fmt, static_cast<unsigned int>(val));
}
}调用:safe_print_int("count = %d", 42); —— 这样至少卡住了非整型输入和大小类型错配。
真正麻烦的是跨平台 ABI 差异:Windows 上 long 是 32 位,Linux x86_64 是 64 位。别想靠记“long 总是 XX 位”来省事,查 sizeof(long) 或改用 int32_t/int64_t 才靠谱。









