c++数值转换

前言: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

原创不易,转载请注明出处!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值