C++ 17 字符串转换

C++ 17 字符串转换

提到 C++17 的字符串转换,最值得记住的是 <charconv> 头文件里的 std::to_charsstd::from_chars。它们提供了一种更轻量、更高性能的数值与字符序列转换方式。

1. 为什么还需要新的字符串转换接口?

在这之前,我们常见的做法有:

  • std::stoi
  • std::stol
  • std::to_string
  • stringstream

这些接口都能完成任务,但也有一些问题:

  • 有的依赖区域设置(locale)
  • 有的性能一般
  • 有的会抛异常
  • stringstream 用起来偏重

to_chars / from_chars 的目标就是提供一个更底层、更直接的转换接口。

2. std::to_chars

std::to_chars 用于把数值写入字符缓冲区。

基本示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <charconv>
#include <array>
#include <iostream>
using namespace std;

int main()
{
array<char, 32> buf{};
auto result = to_chars(buf.data(), buf.data() + buf.size(), 12345);

if (result.ec == errc()) {
cout.write(buf.data(), result.ptr - buf.data());
cout << endl;
}

return 0;
}

输出:

1
12345

特点

  • 不分配内存
  • 不抛异常
  • 使用调用者提供的缓冲区

3. std::from_chars

std::from_chars 用于从字符序列解析数值。

基本示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <charconv>
#include <iostream>
using namespace std;

int main()
{
const char* str = "2024";
int value = 0;

auto result = from_chars(str, str + 4, value);

if (result.ec == errc()) {
cout << value << endl;
}

return 0;
}

输出:

1
2024

4. 和 stoi / to_string 相比有什么区别?

4.1 不抛异常

from_charsto_chars 用错误码表示结果:

1
result.ec == std::errc()

这样在高频转换场景里会更稳一些。

4.2 更偏底层

你要自己准备缓冲区,也要自己处理长度,所以它没有那么“傻瓜式”,但换来的就是更轻量。

4.3 更适合性能敏感场景

比如日志系统、协议解析、序列化组件这类代码,charconv 往往比 stringstream 更合适。

5. 一个解析示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <charconv>
#include <iostream>
using namespace std;

int main()
{
string text = "345xyz";
int value = 0;

auto ret = from_chars(text.data(), text.data() + text.size(), value);

if (ret.ec == errc()) {
cout << "value = " << value << endl;
cout << "remain = " << string(ret.ptr, text.data() + text.size()) << endl;
}

return 0;
}

这里 ret.ptr 可以帮助我们知道解析停在了哪里。

6. 使用时要注意的点

6.1 它操作的是字符区间,不是 std::string 返回值

这套接口比较偏 C 风格缓冲区思路,所以第一次接触时可能会觉得不如 stoi 直观。

6.2 需要自己保证缓冲区足够大

如果 to_chars 的目标缓冲区太小,转换会失败。

6.3 浮点支持情况要看实现

整数支持通常没问题,但浮点相关支持在不同编译器和标准库实现里,历史上兼容情况差异更明显一些。

总结

C++17<charconv> 给数值和字符串之间的转换提供了一套更底层、更轻量的方案。
如果你只是偶尔做简单转换,stoito_string 仍然够用;但如果你在意性能、异常开销或者想手动控制缓冲区,那么 std::to_charsstd::from_chars 就更值得关注。