c++oding="utf-8" ?>
std::print比printf更安全,因其格式串在编译期解析并强制类型匹配,类型不匹配直接编译失败而非运行时未定义行为;不支持%d等c风格格式符,仅支持{:05d}等python风格说明符,且需配合std::formatter特化支持自定义类型。

std::print 为什么比 printf 更安全
printf 的格式字符串在运行时才解析,类型不匹配就直接 UB(比如用 %d 打印 std::string),编译器几乎不检查。而 std::print 是编译期检查的:参数类型必须能被格式化器识别,否则报错,不是崩溃。
- 错误现象:
printf("%s", 42)可能静默崩掉;std::print("{}", 42)直接编译失败 - 使用场景:适合需要强类型保障的日志、调试输出,尤其配合自定义类型(只要提供
std::formatter特化) - 注意点:不支持
%08x这类 C 风格修饰符,得用{:08x}(Python 风格格式说明符) - 示例:
std::print("Value: {:05d}, Name: {}\n", 7, "alice");
std::println 自动换行但不 flush,和 cout
std::println 等价于 std::print(...); std::print("\n"),只加换行符,不调用 std::flush。而 std::cout 每次都强制刷缓冲区,性能差很多。
- 常见错误:误以为
std::println会 flush,结果日志没实时出现(尤其重定向到文件或管道时) - 正确做法:需要立即可见时,显式加
std::print("\n"); std::fflush(stdout);或用std::cout - 性能影响:在循环中打千条日志,
std::println比std::cout 快 2–3 倍(实测 clang 17 + libc++) - 示例:
std::println("Processing item {}", i); // 不 flush
怎么把旧代码里的 printf/cout 快速迁移到 std::print
不能无脑替换。C 风格格式串要转成大括号形式,且 std::print 不接受可变参数指针(va_list),所以封装了 printf 的日志宏得重写。
- 参数差异:
printf("%.*s", len, ptr)→std::print("{:.{}s}", std::string_view{ptr, len}, len) - 字符串字面量需加
std::string_view或用"{}"_sv(C++23 字符串字面量)避免隐式转换开销 - 宏迁移示例(简化版):
// 旧宏 #define LOG(fmt, ...) printf("[LOG] " fmt "\n", ##__VA_ARGS__)
// 新宏(C++23)
define LOG(...) std::println("[LOG] {}", std::make_format_args(__VA_ARGS__))
- 兼容性注意:MSVC 19.35+、GCC 13+、Clang 15+ 才支持;老编译器只能用fmt::print 替代
std::print 不支持 ostream 绑定,遇到文件/stringstream 怎么办
std::print 默认输出到 stdout,没有重载接受 std::ostream& 的版本。想写入文件或内存,得用 std::format + 手动写入。
- 常见坑:写
std::print(file_stream, "xxx")编译不过,因为没这个重载 - 正确路径:
- 写文件:
auto s = std::format("Hello {}", name); file_stream - 写 stringstream:
ss
- 写文件:
- 性能提示:
std::format返回std::string,若追求零拷贝,可预分配 buffer 并用std::vformat_to(C++23) - 示例:
std::string buf; buf.resize(128); std::vformat_to(buf.begin(), "{}", std::make_format_args(42));
C++23 的 std::print 和 std::println 真正的价值不在语法糖,而在编译期安全和统一格式语法;但它们刻意放弃对流对象的支持,意味着你得为不同目标(终端、文件、网络)选择不同组合,这点容易被忽略。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











