目录
[C 语言中的格式化函数对比](#C 语言中的格式化函数对比)
[1. printf / fprintf / sprintf 的异同](#1. printf / fprintf / sprintf 的异同)
[C++ 中的字符串格式化](#C++ 中的字符串格式化)
[1. 流式输出 (std::ostringstream)](#1. 流式输出 (std::ostringstream))
[2. C++20/23 格式化库 (std::format,需编译器支持)](#2. C++20/23 格式化库 (std::format,需编译器支持))
C 语言中的格式化函数对比
1. printf / fprintf / sprintf 的异同
| 函数 | 输出目标 | 返回值 | 主要用途 |
|---|---|---|---|
printf |
标准输出 (stdout) |
写入的字符数 | 控制台输出 |
fprintf |
任意文件流 (FILE*) |
写入的字符数 | 文件或日志写入 |
sprintf |
字符数组 (char[]) |
写入的字符数 | 内存中构造字符串 |
代码示例:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
const int len = 128;
time_t tx = time(nullptr);
struct tm* p = localtime(&tx);
char buff[len] = {};
fprintf(stdout, "%4d/%02d/%02d/-%02d:%02d:%d\n",
p->tm_year+1900,p->tm_mon+1,
p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
sprintf(buff, "%4d/%02d/%02d/-%02d:%02d:%d\n",
p->tm_year + 1900, p->tm_mon + 1,
p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
cout << buff << endl;
return 0;
}
关键风险: sprintf 无缓冲区越界检查 ,若格式化后的字符串长度超过 buff 的大小会导致缓冲区溢出。 ✅ 安全改进: 使用 snprintf 指定最大写入长度:
cpp
snprintf(buff, len, "..."); // 保证不超过 len-1 字节
C++ 中的字符串格式化
1. 流式输出 (std::ostringstream)
核心优势:
-
类型安全 :无需手动匹配格式符(如
%dvs%s) -
内存安全:自动管理缓冲区,无需预分配固定大小
-
扩展性 :支持自定义类型的
operator<<重载
代码示例:
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>
#include <sstream>
using namespace std;
int main()
{
time_t tx = time(nullptr);
struct tm *tmbuf = localtime(&tx);
ostringstream oss;
oss << (tmbuf->tm_year + 1900) << "/"
<< (tmbuf->tm_mon + 1) << "/"
<< tmbuf->tm_mday << " "
<< tmbuf->tm_hour << ":"
<< tmbuf->tm_min << ":"
<< tmbuf->tm_sec;
string datetime = oss.str();
cout << datetime << endl;
return 0;
}
2. C++20/23 格式化库 (std::format,需编译器支持)
cpp
#include <format>
int main() {
int year = 2024, month = 7, day = 17;
auto str = format("{:04}/{:02}/{:02}", year, month, day);
// 输出 "2024/07/17"
return 0;
}
特点:
-
类似 Python 的
str.format语法 -
编译时格式字符串检查(C++20 起支持
consteval) -
高性能且类型安全
跨语言对比与最佳实践
| 特性 | C (sprintf) |
C++ (ostringstream) |
C++20 (std::format) |
|---|---|---|---|
| 类型安全 | ❌ 易出错 | ✅ 安全 | ✅ 安全 |
| 缓冲区溢出风险 | ❌ 高风险 | ✅ 无 | ✅ 无 |
| 格式化灵活性 | ✅ 高 | ⚠️ 中等(需手动填充) | ✅ 高 |
| 性能 | ✅ 高 | ⚠️ 中等 | ✅ 高 |
| 代码可读性 | ❌ 低 | ✅ 高 | ✅ 高 |
实战建议
-
C 语言场景
-
始终优先使用
snprintf而非sprintf -
检查返回值以确认实际写入长度:
cppif (n >= len) { /* 处理截断 */ }
-
-
C++ 场景
-
通用场景 :使用
std::ostringstream,适合简单拼接和类型安全需求 -
高性能/复杂格式化 :使用
std::format(需 C++20) -
旧代码兼容 :可封装
snprintf到std::string:cppstring format(const char* fmt, ...) { char buf[1024]; va_list args; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); return buf; }
-
-
时间格式化专用工具 C++11 起可使用
<chrono>+std::put_time:cpp#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <sstream> #include <iomanip> #include <chrono> using namespace std; int main() { auto now = chrono::system_clock::now(); time_t t = chrono::system_clock::to_time_t(now); ostringstream oss; oss << put_time(localtime(&t), "%Y/%m/%d %H:%M:%S"); string datetime = oss.str(); cout << datetime << endl; return 0; }
总结
-
C 语言 :用
snprintf替代sprintf,并严格检查缓冲区大小 -
C++ 旧标准 :
std::ostringstream提供安全但稍显冗长的格式化 -
C++20+ :
std::format是兼顾性能、安全与可读性的终极方案 -
时间处理 :优先使用
<chrono>和std::put_time避免手动计算