C++20格式化字符串:std::format的使用与实践

在C++编程中,字符串格式化是一项常见的任务。在C++20引入std::format之前,开发者通常依赖于一些传统的解决方案,如printf系列函数、sstream,或者第三方库如boost.format。然而,这些方法在代码可读性、类型安全性和灵活性方面存在一定的局限性。本文将首先回顾这些旧方法及其问题,然后详细介绍C++20中std::format的使用与实践。

一、C++20之前的字符串格式化方法

在C++20之前,开发者主要依赖以下几种方法进行字符串格式化:

  1. printf系列函数
  2. sstream
  3. 第三方库(如boost.format

1. printf系列函数

printf函数是C语言中常用的字符串格式化工具,它通过格式说明符来指定参数的类型和格式。虽然简单易用,但printf存在一些严重的问题:

  • 类型不安全printf无法检查参数的类型和数量是否与格式说明符匹配,容易导致运行时错误。
  • 难以维护:复杂的格式化需求需要多个printf调用,代码可读性差。

示例:

#include <cstdio>int main() {printf("整数: %d, 浮点数: %.2f\n", 123, 45.67);return 0;
}

输出:

整数: 123, 浮点数: 45.67

2. sstream

sstream是C++标准库中提供的类,通过std::ostringstream可以方便地进行字符串格式化。sstream具有类型安全性和可维护性的优点,但其语法相对繁琐,不够灵活。

示例:

#include <sstream>
#include <string>int main() {std::ostringstream oss;oss << "整数: " << 123 << ", 浮点数: " << 45.67;std::string result = oss.str();// result 的值为 "整数: 123, 浮点数: 45.67"return 0;
}

优点:

  • 类型安全:编译器会检查操作数的类型,避免类型不匹配的问题。
  • 可维护性高:代码结构清晰,易于维护。

缺点:

  • 语法不够灵活:无法像printfstd::format那样通过格式说明符指定复杂的格式。

3. 第三方库(如boost.format

boost.format是Boost库中提供的一个格式化字符串工具,它提供了类似于Python的格式化功能。虽然功能强大,但需要引入额外的依赖,可能不适合所有项目。

示例:

#include <boost/format.hpp>
#include <string>int main() {std::string result = boost::format("整数: %1%, 浮点数: %.2f") % 123 % 45.67;// result 的值为 "整数: 123, 浮点数: 45.67"return 0;
}

优点:

  • 功能强大:支持复杂的格式化需求。
  • 类型安全:编译器会检查参数的类型和数量是否匹配。

缺点:

  • 需要引入第三方库:增加了项目的依赖。
  • 学习成本较高:需要学习Boost库的使用方法。

二、C++20之前的字符串格式化方法对比

下表对C++20之前的几种字符串格式化方法进行了对比,展示了它们的常规用法和主要问题:

方法名称示例代码输出结果主要问题
printfprintf("整数: %d, 浮点数: %.2f\n", 123, 45.67);整数: 123, 浮点数: 45.67类型不安全,难以维护
sstreamoss << "整数: " << 123 << ", 浮点数: " << 45.67;整数: 123, 浮点数: 45.67语法繁琐,不够灵活
boost.formatboost::format("整数: %1%, 浮点数: %.2f") % 123 % 45.67;整数: 123, 浮点数: 45.67需要第三方库,学习成本较高

三、C++20的std::format:现代、安全、灵活的字符串格式化

C++20引入的std::format库,整合了上述方法的优点,提供了一种现代、安全、灵活的字符串格式化解决方案。它支持与Python类似的格式化语法,能够处理多种数据类型,并且可以自定义格式化方式。

1. std::format的基本用法

std::format的基本语法如下:

#include <format>
#include <string>int main() {std::string result = std::format("Hello, {}!", "World");// result 的值为 "Hello, World!"return 0;
}

2. 格式说明符

std::format支持多种格式说明符,可以对整数、浮点数、字符串等多种数据类型进行格式化。

a. 整数格式化

std::string result = std::format("整数: {:d}, 十六进制: {:x}, 八进制: {:o}", 123, 123, 123);
// result 的值为 "整数: 123, 十六进制: 7b, 八进制: 173"
  • :d:以十进制形式显示整数。
  • :x:以小写十六进制形式显示整数。
  • :o:以八进制形式显示整数。

b. 浮点数格式化

std::string result = std::format("浮点数: {:f}, 科学计数法: {:e}, 保留三位小数: {:.3f}", 123.456, 123.456, 123.456);
// result 的值为 "浮点数: 123.456000, 科学计数法: 1.234560e+02, 保留三位小数: 123.456"
  • :f:以固定点格式显示浮点数。
  • :e:以科学计数法显示浮点数。
  • :.3f:保留三位小数。

c. 字符串格式化

std::string result = std::format("字符串: {}", "Hello, World!");
// result 的值为 "字符串: Hello, World!"

字符串的格式化相对简单,直接使用{}即可。

3. 自定义格式

std::format允许通过自定义格式说明符来实现更复杂的格式化需求。

a. 对齐和填充

std::string result = std::format("左对齐: {:<10}, 右对齐: {:>10}, 居中对齐: {:^10}", "a", "b", "c");
// result 的值为 "左对齐: a         , 右对齐:         b, 居中对齐:    c    "
  • :<10:左对齐,总宽度为10个字符,不足部分用空格填充。
  • :>10:右对齐,总宽度为10个字符,不足部分用空格填充。
  • :^10:居中对齐,总宽度为10个字符,不足部分用空格填充。

b. 自定义填充字符

std::string result = std::format("左对齐: {:*<10}, 右对齐: {:*>10}, 居中对齐: {:*^10}", "a", "b", "c");
// result 的值为 "左对齐: a*********, 右对齐: *********b, 居中对齐: **c*******"

通过在格式说明符中添加填充字符(如*),可以自定义填充方式。

4. 格式化日期和时间

std::format可以与std::chrono库结合使用,实现日期和时间的格式化。

#include <format>
#include <chrono>
#include <string>int main() {auto now = std::chrono::system_clock::now();std::string time_str = std::format("{:%Y-%m-%d %H:%M:%S}", now);// time_str 的值为类似 "2023-10-05 14:23:45" 的字符串return 0;
}
  • %Y:四位年份。
  • %m:两位月份。
  • %d:两位日期。
  • %H:两位小时(24小时制)。
  • %M:两位分钟。
  • %S:两位秒。

5. 其他功能

a. 格式化布尔值

std::format可以格式化布尔值为truefalse

std::string result = std::format("布尔值: {}", true);
// result 的值为 "布尔值: true"

b. 格式化指针

std::format可以格式化指针为十六进制地址。

int value = 42;
std::string result = std::format("指针地址: {:p}", &value);
// result 的值为类似 "指针地址: 0x7ffeeb0b6c3c" 的字符串

c. 格式化枚举

std::format可以格式化枚举为整数或字符串(需要自定义格式化器)。

enum class Color { Red, Green, Blue };std::string result = std::format("{:d}", Color::Red);
// result 的值为 "0"

四、替代方案

如果你的编译器暂时不支持C++20的std::format,可以考虑使用第三方库,如fmt库,它提供了类似的功能,并且已经被广泛使用。

#include <fmt/core.h>
#include <string>int main() {std::string result = fmt::format("Hello, {}!", "World");// result 的值为 "Hello, World!"return 0;
}

五、总结

C++20的std::format是一个非常强大的工具,能够方便地进行字符串格式化。它支持多种数据类型和格式说明符,并且可以与std::chrono等库结合使用,实现复杂的格式化需求。如果你的项目支持C++20,那么std::format是一个值得尝试的工具。希望本文能够帮助你更好地理解和使用C++20的std::format

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98313.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【漏洞复现】CVE-2025-8088|WinRAR 路径穿越漏洞:从原理到蓝屏攻击全流程

【漏洞复现】CVE-2025-8088&#xff5c;WinRAR 路径穿越漏洞&#xff1a;从原理到蓝屏攻击全流程 前言 WinRAR 作为 Windows 平台最常用的压缩管理工具之一&#xff0c;几乎是每台电脑的 “标配软件”。但在 2025 年 8 月&#xff0c;一款影响范围覆盖 WinRAR 0 至 7.12 全版本…

uniapp中使用echarts并且支持pc端的拖动、拖拽和其他交互事件

npm install echarts -D ​ // "echarts": "^5.3.2", [推荐版本] // "zrender": "^5.3.2" [如果报错的话就安装这个]<template><view class"container"><view id"myChart" class"chart"…

Qt中QProxyStyledrawControl函数4个参数的意义

Qt中QProxyStyle::drawControl函数4个参数的意义 我们来详细解释一下 Qt 中 QProxyStyle::drawControl 函数的四个参数。 这个函数是 Qt 样式系统中的一个核心方法&#xff0c;用于绘制标准 UI 元素&#xff08;如按钮、复选框、菜单栏等&#xff09;。当你继承 QProxyStyle 并…

idf-esp32 PWM呼吸灯(LEDC头文件)

相关宏和变量#define LED_PIN GPIO_NUM_3 #define LEDC_CHANNEL LEDC_CHANNEL_0 #define LEDC_TIMER LEDC_TIMER_0 #define LEDC_MODE LEDC_LOW_SPEED_MODE #define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 2^13 8192级亮度 #define LEDC_FREQUENCY 50…

PLC_博图系列☞基本指令”S_ODTS:分配保持型接通延时定时器参数并启动“

PLC_博图系列☞基本指令”S_ODTS&#xff1a;分配保持型接通延时定时器参数并启动“ 文章目录PLC_博图系列☞基本指令”S_ODTS&#xff1a;分配保持型接通延时定时器参数并启动“背景介绍S_ODTS&#xff1a; 分配保持型接通延时定时器参数并启动说明参数脉冲时序图示例关键字&a…

OneCode 可视化揭秘系列(三):AI MCP驱动的智能工作流逻辑编排

OneCode 可视化揭秘系列&#xff08;三&#xff09;&#xff1a;AI MCP驱动的智能工作流逻辑编排 引言 在前两篇系列博文中&#xff0c;我们详细探讨了OneCode可视化动作的基础配置与界面设计&#xff0c;以及组件交互与数据流管理。在本篇文章中&#xff0c;我们将深入剖析逻辑…

TypeORM、Sequelize、Hibernate 的优缺点对比:新手常见 SQL 与 ORM 踩坑总结

1. ORM 与关系型数据库&#xff08;MySQL、PostgreSQL&#xff09; 的使用 SQL 语句编写&#xff08;JOIN、GROUP BY、索引使用、事务控制&#xff09;与 ORM 映射&#xff08;如 Sequelize、TypeORM、Hibernate&#xff09;之间的差异会让新手非常纠结&#xff1b;尤其是理解…

JavaScript 创建型设计模式详解

1. 单例模式1.1. 使用场景在前端开发中&#xff0c;全局状态管理、配置信息、数据库连接等往往需要在应用中只存在一个实例&#xff0c;避免多次实例化带来的数据不一致性。例如&#xff0c;在一个前端应用中&#xff0c;全局的 loading 状态通常需要一个单例模式来确保其唯一性…

k8s除了主server服务器可正常使用kubectl命令,其他节点不能使用原因,以及如何在其他k8s节点正常使用kubectl命令??

kubectl 并不是“只能”在主节点&#xff08;Control Plane Node&#xff09;使用&#xff0c;而是因为它需要访问 Kubernetes 的 kube-apiserver&#xff0c;而 kube-apiserver 通常只在主节点上运行并监听内部网络。简单来说kubectl 需要连接 kube-apiserver&#xff01;&…

Custom SRP - Complex Maps

https://catlikecoding.com/unity/tutorials/custom-srp/complex-maps/1 创建材质球我们的材质已经支持光照,并且支持 Albedo 和 Emission 贴图.创建材质球,并应用下面的电路板的图分别作为 albedo emission设置材质球的金属度为 1 , 光滑度为 0.952 Mask Map在 albedo 图上的不…

repo 学习教程

你现在会用 git 了&#xff0c;接下来学 repo&#xff08;Google 推出来的多仓库管理工具&#xff09;&#xff0c;其实就是在 Git 的基础上做了一层封装&#xff0c;方便同时管理很多 Git 仓库。像 Android 源码、Rockchip 全套 SDK 都是靠 repo 来拉取和管理的。 我给你分几个…

[SWERC 2020] Safe Distance题解

[SWERC 2020] Safe Distance 题意 给定 NNN 个点与一个坐标 (X,Y)(X,Y)(X,Y)&#xff0c;求从点 (0,0)(0,0)(0,0) 到点 (X,Y)(X,Y)(X,Y) 规划一条路线&#xff0c;不能走出 (0,0)(0,0)(0,0) 与 (X,Y)(X,Y)(X,Y) 间形成的矩形&#xff0c;使得通过这条路线时距离最近的点的距离…

Rewind-你人生的搜索引擎

本文转载自&#xff1a;Rewind-你人生的搜索引擎 - Hello123工具导航 ** 一、&#x1f50d; Rewind 是什么&#xff1f;你的数字记忆增强神器 Rewind 是一款人工智能驱动的个人记忆助手&#xff0c;就像为你配备了一个「数字第二大脑」。它能自动记录、保存并索引你在电脑和手…

开发小点 - 存

开发小点 1.Req注解 EqualsAndHashCode(callSuper true) Data public class BillSituationReq extends BillQueryReq {/*** Whether to display the ring ratio, default is not displayed*/ApiModelProperty("Whether to Display YoY Comparison")private Boolean …

只会npm install?这5个隐藏技巧让你效率翻倍!

原文链接&#xff1a;https://mp.weixin.qq.com/s/nijxVWj-E5U08DX2fl3vgg最近有个刚学前端的小伙伴问我&#xff1a;“为什么我的node_modules这么大&#xff1f;为什么别人装依赖那么快&#xff1f;npx到底是啥玩意儿&#xff1f;” 相信不少人都跟他一样&#xff0c;对npm的…

(二).net面试(static)

文章目录项目地址一、基础501.1 new keyword1.2 static class vs. static method1. static class2. static method3. static constructor 静态构造函数4. 静态成员的生命周期1.3 LinQ1.what is LinQ2. List<T>、IEnumerable<T>、IQueryable<T>3. 在数据库里用…

docker,本地目录挂载

理解Docker本地目录挂载的基本概念Docker本地目录挂载允许容器与宿主机共享文件或目录&#xff0c;实现数据持久化和实时交互。挂载方式分为bind mount和volume两种&#xff0c;前者直接映射宿主机路径&#xff0c;后者由Docker管理存储路径。本地目录挂载的核心方法bind mount…

IO多路复用相关知识

select、poll、epoll 在传入的性能差异是不是体现在&#xff0c;当有新的连接过来&#xff0c;此时需要将新的fd传入到内核中&#xff0c;但是poll/select需要出入整个数组&#xff0c;而epoll方式只需要出入单个fd&#xff1f; 1. select/poll 的情况它们没有内核中“长期保存…

【CF】Day139——杂题 (绝对值变换 | 异或 + 二分 | 随机数据 + 图论)

B. Meeting on the Line题目&#xff1a;思路&#xff1a;数形结合首先考虑如果没有 t 的影响该怎么写显然我们就是让最大时间最小化&#xff0c;那么显然选择最左端点和最右端点的中间值即可&#xff0c;即 (mi mx) / 2&#xff0c;那么现在有了 t 该怎么办我们不妨考虑拆开绝…

在 Ubuntu 上安装和配置 PostgreSQL 实录

一、查看ubuntu版本 lsb_release -a postgresq尽量安装在新的稳定版本的ubuntu上 二、安装postgresql 2.1 直接安装 sudo apt install postgresql 结果如下 2.2 使用PPA源安装 Ubuntu官方源提供了PostgreSQL的PPA(Personal Package Archive),通过PPA源安装可以确保获取…