C++17中增加字符序列与数值之间转换的函数

本文介绍了C++17中新增的std::to_chars和std::from_chars函数,用于字符序列与数值之间的高效转换,对比了它们与std::stringstream和std::to_string在性能和灵活性方面的特点。
摘要由CSDN通过智能技术生成

      C++17中引入了标准头文件<charconv>提供了用于字符序列与数值之间转换的函数。
      1.std::to_chars:用于将数值转换为相应的字符表示形式并将结果存储在缓冲区中。其返回std::to_chars_result类型的对象,包含两个成员:
      (1).ptr:指向所写入字符的结束指针之后的第一个字符的指针;
      (2).ec:是一个错误代码,决定转换是否成功。如果转换成功,错误代码被设置为errc,否则如果发生错误,它将被设置为错误代码。
      2.std::from_chars:用于将数值的字符表示形式转换为其相应的数值表示形式。其返回std::from_chars_result类型的对象,包含两个成员:
      (1).ptr:指向所写入字符的结束指针之后的第一个字符的指针;
      (2).ec:是一个错误代码,决定转换是否成功。如果转换成功,错误代码被设置为errc,否则如果发生错误,它将被设置为错误代码。

      std::stringstream:重量级
      std::to_string:可能涉及动态分配
      std::to_chars:被设计为占用尽可能少的空间,你提供缓冲区,唯一的开销是确保缓冲区足够大。使用std::to_chars的代码不需要任何动态分配。它在格式选项方面也更加灵活,尤其对于浮点值,std::to_string没有格式化选项
      std::from_chars:是一个轻量级解析器,不需要进行任何动态分配。
      如果没有指定精度,对于浮点数,std::to_chars和std::from_chars还提供双向保证:即保证数值被转换为字符序列之后如果再转换回来还是原来的数值。注意:只有当在同一个实现上读写时这个保证才成立

      以下为测试代码:

int test_charconv()
{
	constexpr int val_int{ 88 };
	constexpr float val_float{ 66.66f };
	constexpr double val_double{ 88.8888 };
	const std::string str1{ "123" }, str2{ "456.789" };

	// std::to_chars: converts an integer or floating-point value to a character sequence
	std::array<char, 10> buffer;
	// 注意:std::errc没有到bool的隐式转换,所以你不能像下面这样检查: if (res.ec) {} or if (!res.ec) {}
	if (auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), val_int); ec == std::errc()) {
		std::cout << "str:" << std::string_view(buffer.data(), ptr - buffer.data()) << "\n"; // str:88

		*ptr = '\0'; // 保证结尾有一个空字符
		std::cout << "buffer:" << buffer.data() << "\n"; // buffer:88
	} else {
		std::cerr << "fail to call to_char:" << std::make_error_code(ec).message() << "\n";
		return -1;
	}

	buffer.fill(0);
	if (auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), val_float); ec == std::errc()) {
		std::cout << "str:" << std::string_view(buffer.data(), ptr - buffer.data()) << "\n"; // str:66.66

		*ptr = '\0'; // 保证结尾有一个空字符
		std::cout << "buffer:" << buffer.data() << "\n"; // buffer:66.66
	} else {
		std::cerr << "fail to call to_char:" << std::make_error_code(ec).message() << "\n";
		return -1;
	}

	buffer.fill(0);
	if (auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), val_double); ec == std::errc()) {
		std::cout << "str:" << std::string_view(buffer.data(), ptr - buffer.data()) << "\n"; // str:88.8888
	} else {
		std::cerr << "fail to call to_char:" << std::make_error_code(ec).message() << "\n";
		return -1;
	}

	// std::from_chars: converts a character sequence to an integer or floating-point value
	int val1{ 0 };
	auto [ptr, ec] = std::from_chars(str1.data(), str1.data() + str1.size(), val1);
	if (ec == std::errc()) // 注意:std::errc没有到bool的隐式转换,所以你不能像下面这样检查: if (res.ec) {} or if (!res.ec) {} 
		std::cout << "val1:" << val1 << "\n"; // val1:123
	else if (ec == std::errc::invalid_argument)
		std::cerr << "Error: this is not a number: " << str1 << "\n";
	else if (ec == std::errc::result_out_of_range)
		std::cerr << "Error: this number is larger than an int: " << str1 << "\n";
	else
		std::cerr << "fail to call from_chars:" << std::make_error_code(ec).message() << "\n";

	float val2{ 0.f };
	auto [ptr2, ec2] = std::from_chars(str2.data(), str2.data() + str2.size(), val2);
	if (ec2 == std::errc())
		std::cout << "val2:" << val2 << "\n"; // val2:456.789
	else if (ec2 == std::errc::invalid_argument)
		std::cerr << "Error: this is not a number: " << str2 << "\n";
	else if (ec2 == std::errc::result_out_of_range)
		std::cerr << "Error: this number is larger than an float: " << str2 << "\n";
	else
		std::cerr << "fail to call from_chars:" << std::make_error_code(ec2).message() << "\n";


	// std::stringstream: int/float/double->std::string
	std::stringstream ss1;
	ss1 << val_int << "," << val_float << "," << val_double;
	std::string str = ss1.str();
	std::cout << "str:" << str << "\n"; // str:88,66.66,88.8888

	std::stringstream ss2;
	ss2 << str1 << "," << str2;
	str = ss2.str();
	std::cout << "str:" << str << "\n"; // str:123,456.789

	// std::to_string: int/float/double->std::string
	str = std::to_string(val_int);
	std::cout << "str:" << str << "\n"; // str:88
	str = std::to_string(val_float);
	std::cout << "str:" << str << "\n"; // str:66.660004
	str = std::to_string(val_double);
	std::cout << "str:" << str << "\n"; // str:88.888800

	// std::stoi, std::stol, std::stoll: std::string->int/long/long long
	auto ret1 = std::stoi(str1);
	std::cout << "ret1:" << ret1 << "\n"; // ret:123

	// std::stoul, std::stoull: std::string->unsigned long/unsigned long long
	auto ret2 = std::stoul(str1);
	std::cout << "ret2:" << ret2 << "\n"; // ret2:123

	// std::stof, std::stod, std::stold: std::string->float/double/long double
	auto ret3 = std::stof(str2);
	std::cout << "ret3:" << ret3 << "\n"; // ret3:456.789

	return 0;
}

      执行结果如下图所示:

      GitHubhttps://github.com/fengbingchun/Messy_Test

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值