前言:c++模板库同时提供了高级数值转换函数和低级转换函数,可以实现数值与字符串之间的转换。
高级数值转换函数
数值转换为字符串
下面的函数可以用于将数值转换为字符串,T可以是int、long、long long、float、double、long double类型(都包含unsigned)。所有这些函数都负责内存分配,它们会创建一个新的string对象并返回。
string to_string(T val);
使用示例:
long double ld{3.14L};
string s{to_string(ld)};
字符串转为数值
下列函数都是定义在std命名空间中的函数,在这些函数的原型中,str表示要转换的字符串,idx是一个指针,这个指针接收第一个为转换的字符的索引,base表示转换过程中使用的进制。idx指针可以是空指针,如果是空指针,则被忽略。如果不能执行任何转换,这些函数会抛出invalid_argument异常。如果转换的值超出了返回类型的范围,则抛出out_of_range异常。
int stoi(const string& str, size_t *idx = 0, int base = 10);
long stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long stoul(const string& str, size_t *idx = 0, int base = 10);
long long stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);
float stof(const string& str, size_t *idx = 0);
double stod(const string& str, size_t *idx = 0);
long double stold(const string& str, size_t *idx = 0);
示例:
const string ss{" 123usb"};
size_t index{0};
int value{stoi(ss, &index)};
cout << format("parsed value = {}", value) << endl;
cout << format("first non-parsed character = '{}'", ss[index]) << endl;
输出结果:
ss value = 123
first non-parsed character = 'u'
stoi()、stol()、stoll()和stoull()接收整数值并且有一个名为base的参数,表明给定的数值应该用什么进制表示。base的默认值为10,采用数字0~9的十进制,bash为16表示16进制。如果base被设为0,函数会按照一下的规则自动计算给定的数字的进制。
-
如果数字以0x或者0X开头,被解析为16进制。
-
如果以0开头,被解析为8进制。
-
其他情况,被解析为10进制。
const string s1{"0123"}; // 按8进制算
const string s2{"0x123"}; // 按16进制算
// 注意输出的结果是10进制
cout << format("s1 = {}, s2 = {}", stoi(s1, 0, 0), stoi(s2, 0, 0)) << endl;
输出结果:
s1 = 83, s2 = 291
低级数值转换
c++同时也提供了很多低级的数值转换函数,这些都定义在< charconv >头文件中。这些函数不执行内存分配,也不直接使用std::string,而是使用由调用者分配的缓冲区。此外,它们还针对性能进行了优化,并且与语言环境无关。最终的结果是这些函数可以比其他高级转换函数快几个数量级。这些函数也是为所谓的完美往返而设计的,这意味着将数值序列化为字符串表示,然后将结果字符串反序列化为数值,结果与原始值完全相同。
如果希望实现高性能、完美折返、独立于语言环境的转换。则应当使用这些函数。例如在数值数据与人类可读格式(如JSON、XML等)之间进行序列化/反序列化。
数值转换为字符串
std::to_chars_result to_chars( char* first, char* last,
IntegerT value, int base = 10 ); // c++17
这里的IntegerT可以是任何有符号或者无符号的整数类型或者char类型。结果是to_chars_result类型,其定义如下:
struct to_chars_result {
char* ptr;
errc ec;
};
如果转换成功,ptr成员将等于所写入字符尾后一位置的指针。如果转换失败(即ec==errc::value_too_large),则它等于last。
参数
first, last | 要写入的字符范围 |
---|---|
value | 要转换到其字符串表示的值 |
base | 使用的整数基底:2 与 36 间的值(含上下限) |
使用示例:
const size_t size{20};
string out(size, ' ');
auto result{to_chars(out.data(), out.data() + out.size(), 123)};
if (result.ec == errc{})
{
cout << out << endl;
}
在C++23前后,还支持float、double、long double类型的转换。
std::to_chars_result
to_chars( char* first, char* last, float value );
std::to_chars_result
to_chars( char* first, char* last, double value );
std::to_chars_result
to_chars( char* first, char* last, long double value );
std::to_chars_result
to_chars( char* first, char* last, float value,
std::chars_format fmt );
std::to_chars_result
to_chars( char* first, char* last, double value,
std::chars_format fmt );
std::to_chars_result
to_chars( char* first, char* last, long double value,
std::chars_format fmt );
std::to_chars_result
to_chars( char* first, char* last, float value,
std::chars_format fmt, int precision );
std::to_chars_result
to_chars( char* first, char* last, double value,
std::chars_format fmt, int precision );
std::to_chars_result
to_chars( char* first, char* last, long double value,
std::chars_format fmt, int precision );
参数
first, last | - | 要写入的字符范围 |
---|---|---|
value | - | 要转换到其字符串表示的值 |
base | - | 使用的整数基底:2 与 36 间的值(含上下限)。 |
fmt | - | 使用的浮点格式 std::chars_format 类型的位掩码 |
precision | - | 使用的浮点精度 |
enum class chars_format {
scientific = /*unspecified*/,
fixed = /*unspecified*/,
hex = /*unspecified*/,
general = fixed | scientific
};
字符串转换为数值
std::from_chars_result
from_chars( const char* first, const char* last,
int& value, int base = 10 );
std::from_chars_result
from_chars( const char* first, const char* last, float& value,
std::chars_format fmt = std::chars_format::general );
std::from_chars_result
from_chars( const char* first, const char* last, double& value,
std::chars_format fmt = std::chars_format::general );
std::from_chars_result
from_chars( const char* first, const char* last, long double& value,
std::chars_format fmt = std::chars_format::general );
参数
first, last | - | 要分析的合法字符范围 |
---|---|---|
value | - | 如果分析成功,存储被分析值的输出参数 |
base | - | 使用的整数基底:2 与 36 间的值(含上下限)。 |
fmt | - | 使用的浮点格式,std::chars_format 类型的位掩码 |
返回类型:
struct from_chars_result {
const char* ptr;
std::errc ec;
};
成功时,返回 std::from_chars_result 类型的值,它的 ptr 指向首个与模式不匹配的字符,或者在所有字符都匹配时指向拥有等于 last 的值
如果没有匹配到任何模式,那么返回 std::from_chars_result 类型的值,它的 ptr 等于 first 且 ec 等于 std::errc::invalid_argument。不修改 value。
如果匹配到模式,但被分析值不在 value 的类型所表示的范围内,那么返回 std::from_chars_result 类型的值,它的 ec 等于 std::errc::result_out_of_range 且 ptr 指向首个不匹配模式的字符。不修改 value。
to_chars()和from_chars()完美往返特性示例:
double value1{0.123};
string out(10, 'Y'); // 10个字符Y
// 将value1转换成字符串写入到out
auto [ptr1, error1]{to_chars(out.data(), out.data() + out.size(), value1)};
if (error1 == errc{})
{
cout << out << ", " << ptr1 << ", " << value1 << endl;
}
double value2;
// 将转换的数值存储到value2中
auto [ptr2, error2]{from_chars(out.data(), out.data() + out.size(), value2)};
if (error2 == errc{})
{
cout << out << ", " << ptr2 << ", " << value2 << endl;
if (value1 == value2)
{
cout << "perfect roundtrip" << endl;
}
else
{
cout << "No perfect roundtrip" << endl;
}
}
输出:
0.123YYYYY, YYYYY, 0.123
0.123YYYYY, YYYYY, 0.123
perfect roundtrip
原创不易,转载请注明出处!