使用string和string_view(二)——数值转换、std::string_view和非标准字符串

发布时间:2026/9/12 8:25:10

使用string和string_view(二)——数值转换、std::string_view和非标准字符串 目录1. 数值转换1.1 高级数值转换函数1.1.1 数值转换为字符串1.1.2 字符串转换为数值1.2 低级数值转换函数1.2.1 数值转换为字符串1.2.2 字符串转换为数值2. std::string_view2.1 引入2.2 string_view转换成string2.3 std::string_view和临时字符串2.4 std::string_view字面量3. 非标准字符串参考1. 数值转换C标准库同时提供了高级数值转换函数和低级数值转换函数。1.1 高级数值转换函数1.1.1 数值转换为字符串下面的函数可用于将数值转换为字符串T可以是(unsigned) int、(unsigned) long、unsigned) long long、float、double以及long double。所有这些函数都负责内存分配它们会创建一个新的string对象并返回。std::string to_string(T val);这些函数的使用非常简单直观。例如下面的代码将long double值转换为字符串。longdoubled{3.14L};std::string s{std::to_string(d)};1.1.2 字符串转换为数值通过下面这组同样在std名称空间中定义的函数可以将字符串转换为数值。在这些函数原型中str表示要转换的字符串idx是一个指针这个指针接收第一个未转换的字符的索引base表示转换过程中使用的进制。idx指针可以是空指针如果是空指针则被忽略。如果不能执行任何转换这些函数会抛出invalid_argument异常。如果转换的值超出返回类型的范围则抛出out_of_range异常。int stoi(const string str, size_t* idx0, int base10);long stol(const string str, size_t* idx0, int base10);unsigned long stoul(const string str, size_t* idx0, int base10);long long stoll(const string str, size_t* idx0, int base10);unsigned long long stoull(const string str, size_t* idx0, int base10);float stof(const string str, size_t* idx0);double stod(const string str, size_t* idx0);long double stold(const string str, size_t* idx0);示例如下conststd::string toParse{ 123USD};size_t index{0};intvalue{stoi(toParse,index)};std::coutstd::format(Parse value: {}\n,value);std::coutstd::format(First non-parsed character: {}\n,toParse[index]);输出如下Parsed value:123First non-parsed character:Ustoi()、stol()、stoul()、stoll()和stoull()接收整数值并且有一个名为base的参数表明了给定的数值应该用什么进制来表示。base的默认值为10采用数字为0-9的十进制base为16表示采用16进制。如果base被设为0函数会按照以下规则自动计算给定数字的进制。1. 如果数字以0x或0X开头则被解析为十六进制数字。2. 如果数字以0开头则被解析为八进制数字。3. 其他情况下被解析为十进制数字。1.2 低级数值转换函数C也提供了许多低级数值转换函数这些都在charconv头文件中定义。这些函数不执行内存分配也不直接使用std::string而使用由调用者分配的缓存区。此外它们还针对性能进行了优化并且与语言环境无关。最终的结果是这些函数可以比其他高级数值转换函数快几个数量级。这些函数也是为所谓的完美往返而设计的这意味着将数值序列化为字符串表示然后将结果字符串反序列为数值结果与原始值完全相同。如果希望实现高性能、完美往返、独立于语言环境的转换则应当使用这些函数。例如在数值数据与人类可读格式(如JSON、XML等)之间进行序列化/反序列化。1.2.1 数值转换为字符串要将整数转换为字符可使用下面一组函数。to_chars_result to_chars(char* first, char* last, IntegerT value, int base10);这里IntegerT可以是任何有符号或者无符号的整数类型或char类型。结果是to_chars_result类型类型定义如下。structto_chars_result{char*ptr;std::errc ec;};如果转换成功ptr成员将等于所写入字符尾后一位置的指针。如果转换失败(即ecstd::errc::value_too_large)则它等于last。示例如下(out.data()返回的是指向out中第一个字符的指针)constsize_t BufferSize{50};std::stringout(BufferSize, );// a string of BufferSize space character.autoresult{std::to_chars(out.data(),out.data()out.size(),12345)};if(result.ecstd::errc{}){/* conversion successful. */std::coutout\n;}使用结构化绑定可以将其写成constsize_t BufferSize{50};std::stringout(BufferSize, );auto[ptr,error]{std::to_chars(out.data(),out.data()out.size(),12345)};if(result.ecstd::errc{}){/* conversion successful. */std::coutout\n;}类似地下面的一组转换函数可用于浮点类型。to_chars_resultto_chars(char*first,char*last,FloatT value);to_chars_resultto_chars(char*first,char*last,FloatT value,chars_format format);to_chars_resultto_chars(char*first,char*last,FloatT value,chars_format format,intprecision);这里FloatT可以是float、double或long double。可使用chars_format标志的组合指定格式enumclasschars_format{scientific,// Style: (-)d.ddde加减ddfixed,// Style: (-)ddd.dddhex,// Style: (-)h.hhhp加减dgeneralfixed|scientific//看下面};默认格式是chars_format::general这将导致to_chars()将浮点数转换为(-)ddd.ddd的十进制表示形式或(-)d.ddde加减dd形式的十进制指数表示形式得到最短的表示形式小数点前至少有一位数字(如果存在)。如果指定了格式但未指定精度将为给定格式自动确定最简短的表示形式最大精度为6个数字。例如constsize_t BufferSize{50};doublevalue{0.314};std::stringout(BufferSize, );auto[ptr,error]{std::to_chars(out.data(),out.data()out.size(),value)};if(errorstd::errc{}){/* conversion successful */std::coutout\n;}1.2.2 字符串转换为数值对于相反的转换即将字符串转换为数值可使用下面的一组函数。from_chars_resultfrom_chars(constchar*first,constchar*last,IntegerTvalue,intbase10);from_chars_resultfrom_chars(constchar*first,constchar*last,FloatTvalue,chars_format formatchars_format::general);from_chars_result的类型定义如下structfrom_chars_result{constchar*ptr;std::errc ec;};结果类型的ptr成员指向第一个未转换字符的指针如果所有字符转换成功则它等于last。如果所有字符都未转换则ptr等于first错误代码的值将为std::errc::invalid_argument。如果解析后的值过大无法由给定类型表示则错误代码的值将是std::errc::result_out_of_range。注意from_chars不会忽略任何前导空白。to_chars()和from_chars()的完美往返特性可以表示如下constsize_t BufferSize{50};doublevalue1{0.314};std::stringout(BufferSize, );auto[ptr1,error1]{std::to_chars(out.data(),out.data()out.size(),value1)};if(error1std::errc{}){std::coutout\n;}doublevalue2{};auto[ptr2,error2]{std::from_chars(out.data(),out.data()out.size(),value2)};if(error2std::errc{}){if(value1value2){std::coutPerfect roundtrip\n;}else{std::coutNo Perfect roundtrip?!?\n;}}2. std::string_view2.1 引入在C17之前为接收只读字符串的函数选择形参一直是一件进退两难的事情它应当是const char*吗那这样的话如果客户使用std::string则必须调用其上的c_str()或者data()来获取const char*。更糟糕的是函数将失去std::string良好的面向对象的方面以及其良好的辅助方法。或许形参应改用const std::string这种情况下始终需要std::string。如果传递一个字符串字面量编码器将默认创建一个临时字符串对象(其中包含字符串字面量的副本)并将该对象传递给函数因此会增加一点开销。有时人们会编写同一函数的多个重载版本一个接收const char*另一个接收const std::string但显然这并不是一个优雅的解决方案。在C17中通过引入std::string_view类解决了所有这些问题std::string_view类是std::basic_string_view类模板的实例化在string_view中定义。string_view基本上就是const std::string的简单替代品但不会产生开销。它从不复制字符串string_view支持与std::string类似的接口。一个例外是缺少c_str()但是data()是可用的。另外string_view添加了remove_prefix(size_t)和remove_suffix(size_t)方法前者将起始指针前移给定的偏移量来收缩字符串后者则将结尾指针倒退给定的偏移量来收缩字符串。如果知道如何使用std::string那么使用std::string_view将变得十分简单如下面的代码片段所示。extractExtension()函数提取给定文件名的扩展名(包括点号)并返回。注意通常按值传递string_view因为它的复制成本极低只包含指向字符串的指针以及字符串的长度。std::string_viewextractExtension(std::string_view filename){returnfilename.substr(filename.rfind(.));// rfind locates the last character . in the string.}该函数可用于所有类型的不同字符串usingnamespacestd::literals;std::string filename{R(c:\temp\my file.ext)};std::coutstd::format(C String: {}\n,extractExtension(filename));constchar*cString{R(c:\temp\my file.ext)};std::coutstd::format(C String: {}\n,extractExtension(cString));std::coutstd::format(Literal: {}\n,extractExtension(R(c:\temp\my file.ext)));在对extractExtension()的所有调用中没有进行一次复制。extractExtension()函数的filename()参数只是指针和长度该函数的返回类型也是如此这十分高效。还有一个string_view构造函数它接收任意原始缓冲区和长度。这可用于从字符缓冲区(并非以NUL终止)构建string_view。如果确实有一个以NUL终止的字符串缓冲区但你已经知道了字符串的长度构造函数不必再次统计字符数目这也是有用的。constchar*raw{/* ... */};size_t length{/* ... */};std::coutstd::format(Raw: {}\n,extractExtension({raw,length}));最后一行代码也可以i写成这样std::cout std::format(Raw: {}\n, extractExtension(std::string_view { raw, length } ));注意在每当函数需要将只读字符串作为一个参数时可使用std::string_view替代const std::string或const char*。2.2 string_view转换成string无法从string_view隐式构建一个string。要么使用一个显示的string构造函数要么使用string_view::data()成员。例如假设有以下接收const std::string的函数。voidhandleExtension(conststd::stringextension){/* ... */}不能采用如下方式调用该函数handleExtension(extractExtension(my file.ext));下面是两个可供使用的选项handleExtension(extractExtension(my file.ext).data());// data() methodhandleExtension(std::string{extractExtension(my file.ext)});// explicit constructor由于同样的原因无法连接一个string和string_view。下面的代码将无法编译std::string str{Hello};std::string_view sv{world};autoresult{strsv};你可以对string_view使用data()方法如下所示。auto result1 { str sv.data() };或者你可以使用append()std::string result2{str};result2.append(sv.data(),sv.size());警告返回字符串的函数应返回const std::string或std::string但不应该返回string_view。返回string_view会带来使返回的string_view无效的风险例如当它指向的字符串需要重新分配时。警告将const string或string_view存储为类的数据成员需要确保它们指向的字符串在对象的生命周期内保持有效状态。存储std::string更安全。2.3 std::string_view和临时字符串永远不要使用string_view保存临时字符串的视图考虑以下示例std::string s{Hello};std::string_view sv{s World!};std::coutsv\n;此代码段具有未定义的行为即运行代码时发生的情况取决于编译器和编译器设置。它可能会打印ello World!“等等。为什么是未定义的行为字符串视图sv的初始化表达式将生成一个临时字符串其中包含”Hello World!”。然后string_view存储指向此临时字符串的指针。在第二行代码的末尾这个临时字符串被销毁留下一个悬空指针的string_view。2.4 std::string_view字面量可使用标准用户定义的字面量sv将字符串字面量解释为std::string_view。例如auto sv { My string_viewsv };标准用户定义的字面量sv需要以下几条using命令之一usingnamespacestd::literals::string_view_literals;usingnamespacestd::string_view_literals;usingnamespacestd::literals;usingnamespacestd;3. 非标准字符串许多C程序员都不使用C风格的字符串这有几个原因。一些程序员只是不知道有string类因为它并不总是C规范的一部分。其他程序员发现CString没有提供他们需要的行为或他们不喜欢std::string对字符编码不感知这一事实所以开发了自己的字符串类型。也许最常见的原因是开发框架和操作系统有自己的表达字符串的方式例如Microsoft MFC中的CString类。它常用于向后兼容或解决遗留问题。在C中启动新项目时提前确定团队如何表达字符串是重要的。务必注意以下几点1. 不应当使用C风格的字符串表示。2. 可对自己所使用框架中可用的字符串功能进行标准化如MFC、QT内置的字符串功能。3. 如果为字符串使用std::string应当使用std::string_view将只读字符串作为参数传递给函数否则看一下你的框架是否支持类似于string_view的类。参考[比] 马克·格雷戈勒著 程序喵大人 惠惠 墨梵 译 C20高级编程(第五版)
延伸阅读

更多相关文章

2026/9/12 8:25:09

Fable 5.1深度解析:Playwright+TypeScript+Node一体化自动化升级指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 8:20:09

SSM框架电商平台开发实战与毕业设计指南

1. 项目概述:SSM框架下的电商平台设计与实现这个基于SSM(SpringSpringMVCMyBatis)框架的电子商务平台毕业设计项目,是Java Web开发领域的典型实战案例。作为一个完整的电商系统,它涵盖了用户管理、商品展示、购物车、订…

2026/9/12 12:10:34

EasyClaw实测:个人效能提升200%的6大应用场景

1. 项目概述"一个人EasyClaw能顶几个人?真实用户的6个使用场景实测报告"这个标题揭示了现代生产力工具如何赋能个人工作效能的主题。EasyClaw作为一款新兴的效率工具,正在改变传统工作模式中的人力资源配置方式。通过6个真实使用场景的实测数据…

2026/9/12 12:10:33

SonarQube在Windows环境下的部署与代码质量管理实践

1. SonarQube核心价值解析SonarQube作为静态代码分析领域的标杆工具,其核心价值在于将代码质量管控从"事后检查"转变为"持续监测"。不同于传统IDE自带的代码检查功能,SonarQube通过独立服务的形式,实现了以下关键能力&am…

2026/9/12 12:10:33

水豚鼠标助手提升视频制作效率的5大技巧

1. 水豚鼠标助手在视频创作中的核心价值作为一名从业8年的视频制作人,我亲测过市面上绝大多数辅助工具,直到去年接触到水豚鼠标助手这款神器,我的视频制作效率直接提升了3倍。这款工具最惊艳的地方在于把鼠标操作变成了可视化创作元素&#x…

2026/9/12 12:05:33

ML-KWS-for-MCU源码拆解:嵌入式语音关键词识别全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码