理论
传统字符串转换
下面列出几种常用的方法:
std::stoi()
更加安全,因为它会抛出异常,但无法处理前导空白字符。std::stringstream
更加灵活,可以处理前导空白字符,但性能略差。std::atoi()
简单快速,但不会抛出异常,如果无法转换会返回 0。std::strtol()
可以处理更复杂的情况,如指定进制,并返回转换过程中遇到的第一个无法转换的字符。
std::stoi() 函数可以将 std::string 类型转换为 int 类型。如果无法转换,将抛出 std::invalid_argument 异常。
示例:
std::string str = "42";
int num = std::stoi(str);
使用 std::stringstream 可以先将 std::string 类型的字符串转换为 std::stringstream 流,然后通过 >> 运算符将其提取到 int 类型的变量中。
示例:
std::string str = "42";
int num;
std::stringstream ss(str);
ss >> num;
std::atoi() 函数可以将 C 风格的字符串(即 const char*)转换为 int 类型。需要注意的是,它不会抛出任何异常,如果无法转换,将返回 0。
示例:
std::string str = "42";
char* endptr;
int num = static_cast<int>(std::strtol(str.c_str(), &endptr, 10));
std::strtol() 函数可以将 C 风格的字符串(即 const char*)转换为 long 类型。它还可以返回转换过程中遇到的第一个无法转换的字符。上述代码中的 endptr 指针指向了转换过程中遇到的第一个无法转换的字符。、
示例:
std::string str = "42";
char* endptr;
int num = static_cast<int>(std::strtol(str.c_str(), &endptr, 10));
所以根据上述,大家能够大致明白,传统模式下的字符串转换,接口多,功能参差不齐,要性能没安全,要安全没性能。所以本次讨论的charconv解决这类问题。
新字符串转换
std::to_chars
和std::from_chars
是C++17引入的两个非常有用的函数,它们可以帮助我们在C++中更高效地进行数字和字符串之间的转换。
std::from_chars
它具有以下特点:
- 更快速高效:
std::from_chars
是直接使用底层 C 标准库的转换函数实现的,因此性能更优。 - 更好的异常处理: 与
std::stoi()
类似,std::from_chars
也会在转换失败时返回一个错误码,而不是抛出异常。 - 无需手动检查:
std::from_chars
会自动检查转换是否成功,开发者只需要检查返回值即可。 - 无需中间转换:
std::from_chars
可以直接从std::string_view
或 C 风格字符串转换,不需要先转换为std::string
。
std::to_chars
它可以将 int
、float
或 double
类型的值转换为字符串。它与前面提到的 std::from_chars
函数是相对应的。
下面让我们具体了解一下 std::to_chars
的用法和特点:
- 简单高效:
std::to_chars
是直接使用底层 C 标准库的转换函数实现的,因此性能较优。 - 无需中间转换:
std::to_chars
可以直接将值转换为 C 风格字符串,不需要先转换为std::string
。 - 返回错误码: 与
std::from_chars
类似,std::to_chars
也会返回一个错误码,表示转换是否成功。 - 支持浮点数转换: 除了整数类型,
std::to_chars
还支持float
和double
类型的转换。
实践
使用to_chars数字转字符串,再使用from_chars转回字符串。
#include <charconv> //新版本头文件
#include <iostream>
#include <string_view>
std::string_view int_toString(int value, char *buffer, size_t size) {
// ptr 转换后返回的时缓冲区结束的位置
auto [ptr, err] = std::to_chars(buffer, buffer + size, value);
if (err != std::errc{})
return {};
return {buffer, static_cast<size_t>(ptr - buffer)};
}
int main() {
char buff[20];
int value = 2333;
std::string_view result = int_toString(value, buff, sizeof(buff));
if (result.empty()) {
std::cerr << "转换失败\n";
return 1;
}
std::cout << "int :" << value << " string " << result << " buff " << buff;
int conv = 0;
auto [_, err] =
std::from_chars(result.data(), result.data() + result.size(), conv);
if (err != std::errc{}) {
std::cerr << "Error converting string to integer." << std::endl;
return 1;
}
std::cout << "\nConverted integer value: " << conv << std::endl;
return 0;
}
输出
int :2333 string 2333 buff 2333
Converted integer value: 2333
总结
这两个函数的主要优点包括:
-
性能优化: 通过避免创建临时的
std::string
对象,可以大幅提高数字和字符串之间转换的效率。 -
出错处理: 这些函数返回一个由指针和错误代码组成的结构体,可以帮助开发者更好地处理转换过程中可能出现的错误。
-
灵活性: 这些函数可以与各种数值类型和字符串表示一起使用,提高了代码的通用性和可复用性。
总的来说,std::to_chars
和std::from_chars
是C++17中非常有价值的新特性,它们可以帮助开发者编写更高效、更安全的数字和字符串转换代码。对于需要频繁进行这种转换的应用程序来说,使用这些函数可以带来显著的性能优势。