C++ String Conversion: Exploring std::from_chars in C++17 to C++26
本文为摘录(或转载),侵删,原文为: https://www.cppstories.com/2018/12/fromchars/
随着引入 C++17,C++标准库通过添加 std::from_chars
来扩展了将文本转换为数字的功能。这个低级、高性能的 API 相较于以前的方法(如 atoi 和 stringstream)提供了显著的优势。在本文中,我们将探讨从 C++17 到 C++26 的字符串转换程序的演变,重点突出了诸如 constexpr 支持和改进的错误处理等关键改进。让我们深入了解细节,看看 std::from_chars
如何可以改变您对字符串转换的方法。
1 Before C++17
- sprintf / snprintf
- sscanf
- atol
- strtol
- strstream
- stringstream
- to_string
- stoi 等函数
而在 C++17 中,新增了一种选项: std::from_chars
!为什么需要新方法?难道旧方法不够好吗?
新的转换例程具有以下特点:
- 不抛出异常
- 不分配内存
- 不支持本地化
- 内存安全
- 错误报告提供有关转换结果的额外信息
虽然 API 可能不太友好,但很容易封装为外观模式。
一个简单的示例:
|
|
2 Converting From Characters to Numbers: from_chars
std::from_chars
,在 <charconv> 头文件中可用,是一组重载函数:用于整数类型和浮点类型。
对于整数类型,我们有以下函数:
|
|
其中,TYPE 展开为所有可用的有符号和无符号整数类型以及 char。
base 可以是从 2 到 36 的数字。
然后是浮点数版本:
|
|
FLOAT_TYPE
展开为 float
、 double
或 long double
。
chars_format
是一个枚举,包含以下值:
- scientific、
- fixed、
- hex 和
- general(是 fixed 和 scientific 的组合)。
所有这些函数(对于整数和浮点数)的返回值是 from_chars_result
:
|
|
from_chars_result
包含有关转换过程的信息。
以下是总结:
| 返回条件 || from_chars_result 的状态 | |——|—————————————————————————-| | 成功 || ptr 指向第一个不匹配模式的字符,或者如果所有字符匹配则为 last 的值,并且 ec 为值初始化状态。 | | 无效转换 || ptr 等于 first,ec 等于 std::errc::invalid_argument。value 未被修改。 | | 超出范围 || 数字太大,无法装入值类型。ec 等于 std::errc::result_out_of_range,ptr 指向第一个不匹配的字符。value 未被修改。 |
2.1 示例
以下是使用 from_chars
将字符串转换为数字的两个示例,一个是整数一个是浮点数。
2.1.1 整数类型
|
|
这个示例很简单,它将一个字符串 str 传递给 from_chars,然后在可能的情况下显示结果并提供附加信息。
你的任务是在编译器资源管理器中运行这段代码。
“12345678901234” 能够装入这个数字吗?或者你是否看到一些来自转换 API 的错误?
2.1.2 浮点数
这里是浮点数版本:
|
|
3 性能
我做了一些基准测试,新例程速度非常快!
一些数字:
- 在 GCC 上,它比 stoi 快大约 4.5 倍,比 atoi 快大约 2.2 倍,比 istringstream 快近 50 倍。
- 在 Clang 上,它比 stoi 快大约 3.5 倍,比 atoi 快 2.7 倍,比 istringstream 快 60 倍!
- MSVC 的性能比 stoi 快约 3 倍,比 atoi 快约 2 倍,比 istringstream 快近 50 倍。
你可以在我的 C++17 书籍中找到这些结果:《C++17 详细信息》。
4 C++23 更新
在 C++23 中,我们为我们的函数得到了一个改进:P2291
std::to_chars()
和 std::from_chars()
的整数重载现在是 constexpr
。
它已经在 GCC 13、Clang 16 和 MSVC 19.34 中实现。
与 std::optional 一起,它还可以在 constexpr 上下文中工作,我们可以创建以下示例:
|
|
在编译器资源管理器中运行
5 C++26 更新
这项工作尚未完成,在 C++26 中看起来我们将有更多的添加:
查看 P2497R0,这个提案已经被接受并包含在 C++26 的工作草案中:
对 <charconv> 函数成功或失败的测试
这一功能已在 GCC 14 和 Clang 18 中实现。
简而言之,from_chars_result(以及 to_chars_result)获得了一个 bool 转换运算符:
|
|
它必须返回 ec =
std::errc{}= 。
这意味着我们的代码可能会更简单:
|
|
可以变成:
|
|
例如:
|
|
6 C++ 中对 std::from_chars 的编译器支持
- Visual Studio:
完全支持 std::from_chars 是在 Visual Studio 2019 版本 16.4 中引入的,浮点支持从 VS 2017 版本 15.7 开始。Visual Studio 2022 包含了 C++23 功能,如对整数重载的 constexpr 支持。 - GCC:
从 GCC 11.0 开始,std::from_chars 提供完整支持,包括整数和浮点转换。最新的 GCC 版本,比如 GCC 13,包含 constexpr 整数支持。 - Clang:
Clang 7.0 引入了对整数转换的初始支持。Clang 16 及以上支持整数重载的 constexpr。
获取最准确和最新的信息,请查看 CppReference、编译器支持。
7 总结
如果你想将文本转换为数字,并且不需要任何额外的功能,如区域设置支持,那么 std::from_chars 可能是最好的选择。它提供了很好的性能,而且更重要的是,你将获得关于转换过程的大量信息(例如扫描了多少个字符)。
这些例程在解析 JSON 文件、三维文本模型表示(如 OBJ 文件格式)等方面可能特别有用。
而且新函数甚至可以在编译时使用(截至 C++23),并且在 C++26 中具有更好的错误检查功能。