C++ 字符串和数字相互转换

字符串转数字

std::strtol & std::strtoll & std::strtoul & std::strtoull

函数原型
#include <cstdlib>

long      strtol( const char *str, char **str_end, int base );
long long strtoll( const char *str, char **str_end, int base );

unsigned long      strtoul( const char *str, char **str_end, int base );
unsigned long long strtoull( const char *str, char **str_end, int base );
#include <cwchar>

long      wcstol( const wchar_t* str, wchar_t** str_end, int base );
long long wcstoll( const wchar_t* str, wchar_t** str_end, int base );

unsigned long      wcstoul( const wchar_t* str, wchar_t** str_end, int base );
unsigned long long wcstoull( const wchar_t* str, wchar_t** str_end, int base );
说明

str 指向的字符串转换为整数

跳过任何空白字符,直到找到第一个非空白字符,然后获取尽可能多的有效的整数字符(基数为 base)。有效整数字符定义如下:

  • 加号(+)或减号(-)
  • 前置 0 表示 base8(八进制)
  • 前置 0x0X,表示 base16(十六进制)
  • 一系列的“数字”(对于 base 大于 10 的还包括字母)

base 的有效值为 {0,2,3,…,36}。二进制的有效数字为 {0, 1},三进制的有效数字为 {0, 1, 2},以此类推。对于 base 大于 10 的情况,有效“数字”包括字母,11 进制包括 A(a)12 进制包括 B(b),…,36 进制包括 Z(z)

如果 base0,将自动检查进制。如果前缀是 0,则为 8 进制,如果前缀为 0x0X,则为 16 进制,其他情况为 10 进制。

str_end 指向需要处理的字符的结尾的下一个字符,如果为空,则忽略。

如果 str 为空或者不满足转换要求,该函数将不会进行转换。

返回值
  • 如果成功,则直接返回转换后的数字类型数值

  • 如果返回值超出类型的范围(out of range),将会产生返回错误,设置 errnoERAGE,并返回对应返回类型的最大或最小值

    • longLONG_MAX, LONG_MIN
    • long longLLONG_MAX, LLONG_MIN
    • unsigned long: ULONG_MAX
    • unsigned long long: ULLONG_MAX
  • 如果不能执行转换,则返回 0

代码例子
#include <cerrno>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>

// 打印值
template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::strtol(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp << "= [" << value << "]";
}

void test(const std::string &str) {
  errno = 0;

  char *p_end{nullptr};
  print(str, std::strtol(str.c_str(), &p_end, 10));
  std::cout << ", p_end point to: [" << std::string(p_end) << "]";

  if (errno == ERANGE) {
    std::cout << ", [out of range]";
  }

  std::cout << '\n';
}

int main() {
  test("    12345");
  test("12345   ");
  test("    12345    ");
  test("12345.abc");
  test("abc 12345");
  test("12345123451");
  test("-12345123451");
}
代码输出结果
std::strtol("    12345")      = [12345], p_end point to: []
std::strtol("12345   ")       = [12345], p_end point to: [   ]
std::strtol("    12345    ")  = [12345], p_end point to: [    ]
std::strtol("12345.abc")      = [12345], p_end point to: [.abc]
std::strtol("abc 12345")      = [0], p_end point to: [abc 12345]
std::strtol("12345123451")    = [2147483647], p_end point to: [], [out of range]
std::strtol("-12345123451")   = [-2147483648], p_end point to: [], [out of range]

std::strtof & std::strtod & std::strtold

函数原型
#include <cstdlib>

float       strtof( const char* str, char** str_end );
double      strtod( const char* str, char** str_end );
long double strtold( const char* str, char** str_end );
#include <cwchar>

float       wcstof( const wchar_t* str, wchar_t** str_end );
double      wcstod( const wchar_t* str, wchar_t** str_end );
long double wcstold( const wchar_t* str, wchar_t** str_end );
说明

str 指向的字符串转换为浮点数

跳过任何空白字符,直到找到第一个非空白字符,然后获取尽可能多的有效的浮点数字符。浮点数字符定义如下:

  • 十进制浮点表达式

    • 加号(+)或减号(-)
    • 可选包含小数点字符的十进制数字的非空序列
    • eE 后跟可选的减号(-)或加号(+)以及非空的十进制数字序列
  • 十六进制浮点表达式

    • 加号(+)或减号(-)
    • 0x0X
    • 可选包含小数点字符的十六进制数字的非空序列
    • pP 后跟可选的减号(-)或加号(+)以及非空的十进制数字序列
  • 无穷大表达式

    • 加号(+)或减号(-)
    • INFINFINITY(忽略大小写)
  • 非数字表达式

    • 加号(+)或减号(-)
    • NANNAN(char_sequence) (NAN 忽略大小写),char_sequence 只能包含数字、拉丁字母和下划线

str_end 指向需要处理的字符的结尾的下一个字符,如果为空,则忽略

16 进制浮点数也有指数表达方式。其指数表达形式和 10 进制的指数表达形式相似,只是将 e 换为了 p。但是意思略有不同。

对于 16 进制浮点数指数,xPn 表示 x 的 16 进制数乘以 2 n 2^n 2n

1.0 p 1 = 1.0 × 2 1 1.0p1 = 1.0 \times 2^1 1.0p1=1.0×21

10.0 p 3 = ( 1 × 16 + 0 × 1 ) × ( 2 3 ) 10.0p3 = (1 \times 16 + 0 \times 1) \times (2^3) 10.0p3=(1×16+0×1)×(23)

12.6 p 3 = ( 1 × 16 + 2 × 1 + 6 × 1 16 ) × ( 2 3 ) = 147 12.6p3 = (1 \times 16 + 2 \times 1 + 6 \times \frac{1}{16}) \times (2^3) = 147 12.6p3=(1×16+2×1+6×161)×(23)=147

返回值
  • 如果成功,则直接返回转换后的数字类型数值

  • 如果返回值超出类型的范围(out of range),将会产生返回错误,设置 errnoERAGE,并返回 HUGE_VAL, HUGE_VALFHUGE_VALL

    • longLONG_MAX, LONG_MIN
    • long longLLONG_MAX, LLONG_MIN
    • unsigned long: ULONG_MAX
    • unsigned long long: ULLONG_MAX
  • 如果不能执行转换,则返回 0

代码例子
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>

// 打印值
template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::strtof(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp << "= [" << value << "]";
}

void test(const std::string &str) {
  errno = 0;

  char *p_end{nullptr};
  print(str, std::strtof(str.c_str(), &p_end));
  std::cout << ", p_end point to: [" << std::string(p_end) << "]";

  if (errno == ERANGE) {
    std::cout << ", [out of range]";
  }

  std::cout << '\n';
}

int main()
{
  test("123.456789123");
  test("-123.456789123");
  test("1.2345e3");
  test("1.2345e-3");
  test("-1.2345e-3");
  test("0x12.6");
  test("0x12.6p3");
  test("nan");
  test("inf");
}
代码输出结果
std::strtof("123.456789123")  = [123.457], p_end point to: []
std::strtof("-123.456789123") = [-123.457], p_end point to: []
std::strtof("1.2345e3")       = [1234.5], p_end point to: []
std::strtof("1.2345e-3")      = [0.0012345], p_end point to: []
std::strtof("-1.2345e-3")     = [-0.0012345], p_end point to: []
std::strtof("0x12.6")         = [18.375], p_end point to: []
std::strtof("0x12.6p3")       = [147], p_end point to: []
std::strtof("nan")            = [nan], p_end point to: []
std::strtof("inf")            = [inf], p_end point to: []

std::atoi & std::atol & std::atoll

函数原型
#include <cstdlib>

int       atoi( const char *str);
long      atol( const char *str);
long long atoll( const char *str);
说明

str 指向的字符串转换为整数

跳过任何空白字符,直到找到第一个非空白字符,然后获取尽可能多的有效的整数字符(基数为 base)。有效整数字符定义如下:

  • 加号(+)或减号(-)
  • 数字

atoi 系列的函数的缺点:

  • 当转换出现错误时,函数不会抛异常也不会报错
  • 对于不执行转换时会返回零,对于原来字符串就是 0 是不好进行判断
返回值
  • 如果成功,则直接返回转换后的数字类型数值
  • 如果返回值超出类型的范围(out of range),返回值为未定义
  • 如果不能执行转换,则返回 0
代码例子
#include <cstdlib>
#include <iostream>
#include <string>
#include <iomanip>

// 打印值
template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::atoi(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp  << "= [" << value << "]\n";
}

void test(const std::string& str)
{
  print(str, std::atoi(str.c_str()));
}

int main()
{
  test("12345");
  test("123.45");
  test("12345 with word");
  test("words 12345");
  test("    12345");
  test("12345   ");
  test("  12345   ");
  test("12345123451");
  test("-12345");
}
代码输出结果
std::atoi("12345")            = [12345]
std::atoi("123.45")           = [123]
std::atoi("12345 with word")  = [12345]
std::atoi("words 12345")      = [0]
std::atoi("    12345")        = [12345]
std::atoi("12345   ")         = [12345]
std::atoi("  12345   ")       = [12345]
std::atoi("12345123451")      = [2147483647]
std::atoi("-12345")           = [-12345]

std::atof

函数原型
#include <cstdlib>

double atof(const char *str);
说明

这里 str 的定义同 std::strtof & std::strtod & std::strtold 中的定义,具体内容见上方⬆️

返回值
  • 如果成功,则直接返回转换后的数字类型数值
  • 如果返回值超出类型的范围(out of range),返回值为未定义
  • 如果不能执行转换,则返回 0.0
代码例子
#include <cstdlib>
#include <iostream>
#include <string>
#include <iomanip>

// 打印值
template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::atof(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp  << "= [" << value << "]\n";
}

void test(const std::string str) {
  print(str, std::atof(str.c_str()));
}

int main() {
  test("0.000000012345");
  test("123.45");
  test("1.2345 with word");
  test("words 1.2345");
  test("    12.345");
  test("12.345   ");
  test("  12.345   ");
  test("-12.345");
  test("12345123451");
  test("15e16");
  test("0x12.6p3");
  test("INF");
  test("NAN");
}
代码输出结果
std::atof("0.000000012345")   = [1.2345e-08]
std::atof("123.45")           = [123.45]
std::atof("1.2345 with word") = [1.2345]
std::atof("words 1.2345")     = [0]
std::atof("    12.345")       = [12.345]
std::atof("12.345   ")        = [12.345]
std::atof("  12.345   ")      = [12.345]
std::atof("-12.345")          = [-12.345]
std::atof("12345123451")      = [1.23451e+10]
std::atof("15e16")            = [1.5e+17]
std::atof("0x12.6p3")         = [147]
std::atof("INF")              = [inf]
std::atof("NAN")              = [nan]

std::stoi & std::stol & std::stoll & std::stoul & std::stoull

函数原型
#include <string>

int       stoi( const std::string& str, std::size_t* pos = nullptr, int base = 10 );
int       stoi( const std::wstring& str, std::size_t* pos = nullptr, int base = 10 );

long      stol( const std::string& str, std::size_t* pos = nullptr, int base = 10 );
long      stol( const std::wstring& str, std::size_t* pos = nullptr, int base = 10 );

long long stoll( const std::string& str, std::size_t* pos = nullptr, int base = 10 );
long long stoll( const std::wstring& str, std::size_t* pos = nullptr, int base = 10 );

unsigned long      stoul( const std::string& str, std::size_t* pos = nullptr, int base = 10 );
unsigned long      stoul( const std::wstring& str, std::size_t* pos = nullptr, int base = 10 );

unsigned long long stoull( const std::string& str, std::size_t* pos = nullptr, int base = 10 );
unsigned long long stoull( const std::wstring& str, std::size_t* pos = nullptr, int base = 10 );
说明

stoi 系列的函数可以支持窄字符和宽字符字符串,其内部实现是调用的 strtol 系列的函数

  • stoi 调用 std::strtol(str.c_str(), &ptr, base)std::wcstol(str.c_str(), &ptr, base)
  • stol 调用 std::strtol(str.c_str(), &ptr, base)std::wcstol(str.c_str(), &ptr, base)
  • stoll 调用 std::strtoll(str.c_str(), &ptr, base)std::wcstoll(str.c_str(), &ptr, base)
  • stoul 调用 std::strtoul(str.c_str(), &ptr, base)std::wcstoul(str.c_str(), &ptr, base)
  • stoull 调用 std::strtoull(str.c_str(), &ptr, base)std::wcstoull(str.c_str(), &ptr, base)

其中 str 字符串的定义和 std::strtol 系列函数中定义相同

如果 pos 不为空,字符串中第一个未处理的字符的索引将存储在 *pos 中,即 strtol 系列函数中 str_end 指向字符的索引

因为 stoi 系列的函数会抛出异常,所以在使用该系列函数式一定要注意加上 try … catch … 块

返回值
  • 如果成功,则直接返回转换后的数字类型数值
  • 如果失败,则会抛出异常
    • std::invalid_argument: 参数无效,不执行转换时抛出该异常
    • std::out_of_range: 转换后超出了指定类型的范围时抛出该异常
代码例子
#include <string>
#include <iostream>
#include <iomanip>

// 打印值
template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::stoi(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp  << "= [" << value << "]";
}

void printException(const std::string &str, const std::exception& e) {
  std::string tmp = "std::stoi(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp  << "= [exception: " << e.what() << "]\n";
}

void test(const std::string& str)
{
  try {
    std::size_t pos{0};
    print(str, std::stoi(str, &pos, 10));
    std::cout << ", pos: " << pos << '\n';
  } catch(const std::exception& e) {
    printException(str, e);
  }
}

int main() {
  test("45");
  test("3.14159");
  test("12345 with word");
  test("word 12345");
  test("12345123451");
}
代码输出结果
std::stoi("45")               = [45], pos: 2
std::stoi("3.14159")          = [3], pos: 1
std::stoi("12345 with word")  = [12345], pos: 5
std::stoi("word 12345")       = [exception: invalid stoi argument]
std::stoi("12345123451")      = [exception: stoi argument out of range]

std::stof & std::stod & std::stold

函数原型
#include <string>

float       stof( const std::string& str, std::size_t* pos = nullptr );
float       stof( const std::wstring& str, std::size_t* pos = nullptr );

double      stod( const std::string& str, std::size_t* pos = nullptr );
double      stod( const std::wstring& str, std::size_t* pos = nullptr );

long double stold( const std::string& str, std::size_t* pos = nullptr );
long double stold( const std::wstring& str, std::size_t* pos = nullptr );
说明

stof 系列的函数可以支持窄字符和宽字符字符串,其内部实现是调用的 strtof 系列的函数

  • stof 调用 std::strtof(str.c_str(), &ptr)std::wcstof(str.c_str(), &ptr)
  • stod 调用 std::strtod(str.c_str(), &ptr)std::wcstod(str.c_str(), &ptr)
  • stold 调用 std::strtold(str.c_str(), &ptr)std::wcstold(str.c_str(), &ptr)

其中 str 字符串的定义和 std::strtof 系列函数中定义相同

如果 pos 不为空,字符串中第一个未处理的字符的索引将存储在 *pos 中,即 strtof 系列函数中 str_end 指向字符的索引

因为 stof 系列的函数会抛出异常,所以在使用该系列函数式一定要注意加上 try … catch … 块

返回值
  • 如果成功,则直接返回转换后的数字类型数值
  • 如果失败,则会抛出异常
    • std::invalid_argument: 参数无效,不执行转换时抛出该异常
    • std::out_of_range: 转换后超出了指定类型的范围时抛出该异常
代码例子
#include <string>
#include <iostream>
#include <iomanip>

// 打印值
template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::stof(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp  << "= [" << value << "]";
}

void printException(const std::string &str, const std::exception& e) {
  std::string tmp = "std::stof(\"" + str + "\") ";
  std::cout << std::setw(30) << std::left << tmp  << "= [exception: " << e.what() << "]\n";
}

void test(const std::string& str)
{
  try {
    std::size_t pos{0};
    print(str, std::stof(str, &pos));
    std::cout << ", pos: " << pos << '\n';
  } catch(const std::exception& e) {
    printException(str, e);
  }
}

int main() {
  test("123.456789123");
  test("-123.456789123");
  test("1.2345e3");
  test("1.2345e-3");
  test("-1.2345e-3");
  test("0x12.6");
  test("0x12.6p3");
}
代码输出结果
std::stof("123.456789123")    = [123.457], pos: 13
std::stof("-123.456789123")   = [-123.457], pos: 14
std::stof("1.2345e3")         = [1234.5], pos: 8
std::stof("1.2345e-3")        = [0.0012345], pos: 9
std::stof("-1.2345e-3")       = [-0.0012345], pos: 10
std::stof("0x12.6")           = [18.375], pos: 6
std::stof("0x12.6p3")         = [147], pos: 8

使用 std::stringstream

#include <iostream>
#include <sstream>
#include <iomanip>

template <typename T>
void string_to_number(const std::string& str, T& number) {
  std::stringstream ss;
  ss << str;
  ss >> number;
  std::cout << "stringstream " << std::setw(7) <<  std::left << typeid(number).name() << " (" << std::quoted(str) << ") = [" << number << "]\n";
}

template <typename T>
void test(const std::string& str) {
  T number;
  string_to_number(str, number);
}

int main() {
  test<int>("12345");
  test<int>("-12345");
  test<int>("12345abc");
  test<int>(" 12345 abc");

  test<float>("123.456789123");
  test<float>("-123.456789123");
  test<float>("1.2345e3");
  test<float>("1.2345e-3");
  test<float>("0x12.6");
  test<float>("0x12.6p3");
}
代码输出结果
stringstream int     ("12345") = [12345]
stringstream int     ("-12345") = [-12345]
stringstream int     ("12345abc") = [12345]
stringstream int     (" 12345 abc") = [12345]
stringstream float   ("123.456789123") = [123.457]
stringstream float   ("-123.456789123") = [-123.457]
stringstream float   ("1.2345e3") = [1234.5]
stringstream float   ("1.2345e-3") = [0.0012345]
stringstream float   ("0x12.6") = [0]
stringstream float   ("0x12.6p3") = [0]

std::from_chars (c++ 17)

函数原型
#include <charconv>

struct from_chars_result {
    const char* ptr;
    std::errc ec;
};

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,
                                  /*see below*/& 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 不会被修改,否则,匹配模式的字符将被转换为对应的类型的值,保存在 value 中。

具体的模式如下:

  • 整数解析器:与 std::strtol 在默认 (“C”) 语言环境中使用的模式相同,除了以下情况

    • base16 时,0x0X 不能被识别
    • 只能识别减号(-),并且仅适用于有符号整数类型的值
  • 浮点数解析器:与 std::strtod 在默认 (“C”) 语言环境中使用的模式相同,除了以下情况

    • 在指数之外无法识别加号(仅允许在开头使用减号)
    • 如果 fmt 设置了 std::chars_format::scientific 但没有设置 std::chars_format::fixed,则指数部分是必需的(否则它是可选的)
    • 如果 fmt 设置了 std::chars_format::fixed 但没有设置 std::chars_format::scientific,则不允许使用可选指数
    • 如果 fmtstd::chars_format::hex,则不允许前缀 0x0X(字符串 0x123 解析为值 0,未解析余数为x123)。
    • 在任何情况下,在根据 std::round_to_nearest 舍入后,结果值是最接近匹配模式的字符串值的至多两个浮点值之一。

该系列的函数不会抛出异常(non-throwing),与语言环境无关(locale-independent),不会分配内存(non-allocating)

需要注意的点:

  • 不支持前置空格
  • 不支持加号(+)开始
  • 对于 16 进制的浮点数,不支持前置的 0x0X
  • 对于浮点数,如果设置 fmtstd::chars_format::scientific,则字符串中必须表示为科学计数表达式(包含 eE 部分)
返回值
  • 转换成功,std::from_chars_resultptr 指向与模式不匹配的第一个字符或者 lastvalue 为转换后的值
  • 如果一个也不匹配(不能转换),std::from_chars_resultptr 指向 firstecstd::errc::incalid_argumentvalue 值保持不变
  • 如果转换后数值超出了返回值类型的范围,则 std::from_chars_resultptr 指向 firstecstd::errc::result_out_of_rangevalue 保持不变
性能
  • On GCC it’s around 4.5x faster than stoi, 2.2x faster than atoi and almost 50x faster than istringstream.
  • On Clang it’s around 3.5x faster than stoi, 2.7x faster than atoi and 60x faster than istringstream!
  • MSVC performs around 3x faster than stoi, ~2x faster than atoi and almost 50x faster than istringstream
代码例子
#include <charconv>
#include <iostream>
#include <string>
#include <string_view>
#include <iomanip>

template<typename T>
void print(const std::string &str, const T &value) {
  std::string tmp = "std::from_chars(\"" + str + "\") ";
  std::cout << std::setw(35) << std::left << tmp << "= [" << value << "]";
}

template<typename T>
void test_integer(const std::string &str, int base = 10) {
  T result;
  auto[p, ec] = std::from_chars(str.data(), str.data() + str.size(), result, base);
  if (ec == std::errc()) {
    print(str, result);
    std::cout << ", p point to [" << p << "]";
  } else if (ec == std::errc::invalid_argument) {
    print(str, "invalid argument");
    std::cout << ", p point to [" << p << "]";
  } else if (ec == std::errc::result_out_of_range) {
    print(str, "result out of range");
    std::cout << ", p point to [" << p << "]";
  }

  std::cout << '\n';
}

template<typename T>
void test_float(const std::string &str, std::chars_format fmt = std::chars_format::general) {
  T result;
  auto[p, ec] = std::from_chars(str.data(), str.data() + str.size(), result, fmt);
  if (ec == std::errc()) {
    print(str, result);
    std::cout << ", p point to [" << p << "]";
  } else if (ec == std::errc::invalid_argument) {
    print(str, "invalid argument");
    std::cout << ", p point to [" << p << "]";
  } else if (ec == std::errc::result_out_of_range) {
    print(str, "result out of range");
    std::cout << ", p point to [" << p << "]";
  }

  std::cout << '\n';
}

int main() {
  test_integer<int>("12345");
  test_integer<int>("    12345");
  test_integer<int>("12345    ");
  test_integer<int>("    12345    ");
  test_integer<int>("12345 with word");
  test_integer<int>("word 12345");
  test_integer<int>("+12345");
  test_integer<int>("-12345");
  test_integer<int>("12", 16);
  test_integer<int>("0x12", 16);

  test_float<float>("123.456789123");
  test_float<float>("-123.456789123");
  test_float<float>("1.2345e3");
  test_float<float>("1.2345e-3");
  test_float<float>("1.2345e+3");
  test_float<float>("12.6", std::chars_format::hex);
  test_float<float>("12.6p3", std::chars_format::hex);
}
代码输出结果
std::from_chars("12345")           = [12345], p point to []
std::from_chars("    12345")       = [invalid argument], p point to [    12345]
std::from_chars("12345    ")       = [12345], p point to [    ]
std::from_chars("    12345    ")   = [invalid argument], p point to [    12345    ]
std::from_chars("12345 with word") = [12345], p point to [ with word]
std::from_chars("word 12345")      = [invalid argument], p point to [word 12345]
std::from_chars("+12345")          = [invalid argument], p point to [+12345]
std::from_chars("-12345")          = [-12345], p point to []
std::from_chars("12")              = [18], p point to []
std::from_chars("0x12")            = [0], p point to [x12]
std::from_chars("123.456789123")   = [123.457], p point to []
std::from_chars("-123.456789123")  = [-123.457], p point to []
std::from_chars("1.2345e3")        = [1234.5], p point to []
std::from_chars("1.2345e-3")       = [0.0012345], p point to []
std::from_chars("1.2345e+3")       = [1234.5], p point to []
std::from_chars("12.6")            = [18.375], p point to []
std::from_chars("12.6p3")          = [147], p point to []

数字转字符串

std::to_string & std::to_wstring

函数原型
std::string to_string( int value );
std::string to_string( long value );
std::string to_string( long long value );
std::string to_string( unsigned value );
std::string to_string( unsigned long value );
std::string to_string( unsigned long long value );
std::string to_string( float value );
std::string to_string( double value );
std::string to_string( long double value );
说明
  • 对于浮点类型 std::to_string 可能会产生意外的结果,因为返回的字符串中的有效位数可能为零
  • std::to_string 依赖当前语言环境进行格式化,因此从多个线程并发调用 std::to_string 可能导致部分序列化
代码例子
#include <iostream>
#include <string>
#include <iomanip>

template <typename T>
void test(T value) {
  std::string str = std::to_string(value);
  std::cout << "std::to_string(\"" << value << "\") = [" << str << "]\n";

  std::wstring wstr = std::to_wstring(value);
  std::wcout << L"std::to_wstring(\"" << value << L"\") = [" << wstr << L"]\n";
}

int main() {
  test(12345);
  test(-12345);
  test(123.45);
  test(1.23e3);
  test(1e-20);
  test(1e30);
}
代码输出结果
std::to_string("12345") = [12345]
std::to_wstring("12345") = [12345]
std::to_string("-12345") = [-12345]
std::to_wstring("-12345") = [-12345]
std::to_string("123.45") = [123.450000]
std::to_wstring("123.45") = [123.450000]
std::to_string("1230") = [1230.000000]
std::to_wstring("1230") = [1230.000000]
std::to_string("1e-20") = [0.000000]
std::to_wstring("1e-20") = [0.000000]
std::to_string("1e+30") = [1000000000000000019884624838656.000000]
std::to_wstring("1e+30") = [1000000000000000019884624838656.000000]

sprintf & snprintf & sprintf_s & snprintf_s

函数原型
#include <cstdio>

int sprintf( char *restrict buffer, const char *restrict format, ... );
int snprintf( char *restrict buffer, size_t bufsz, const char *restrict format, ... );
int sprintf_s(char *restrict buffer, rsize_t bufsz, const char *restrict format, ...);
int snprintf_s(char *restrict buffer, rsize_t bufsz, const char *restrict format, ...);
说明

格式字符串由普通的多字节字符组成(% 除外),并按指定的格式进行转换:

转换字符描述
%格式转换标志,如果想要转换为 %,需要使用 %%
c单个字符
s字符串
d & i十进制带符号数
o八进制无符号数
x & X十六进制无符号数
u十进制无符号数
f & F十进制浮点数
e & E十进制指数浮点数
a & A十六进制浮点数
g & G十进制浮点数或十进制指数浮点数
  • 浮点转换函数将无穷大转换为 infinfinity。使用哪一个是实现定义的
  • 非数字转换为 nannan(char_sequence)
返回

sprintf: 写入缓冲区的字符数(不包括终止空字符),如果发生编码错误(对于字符串和字符转换说明符),则为负值
snprintf: 如果忽略 bufsz,返回为将写入缓冲区的字符数(不包括终止空字符),或者如果发生编码错误(对于字符串和字符转换说明符)则为负值
sprintf_s: 写入缓冲区的字符数,不包括空字符(只要缓冲区不是空指针并且 bufsz 不为零且不大于 RSIZE_MAX),或运行时约束违规为零,编码错误为负值
snprintf_s: 不包括终止空字符的字符数(只要缓冲区不是空指针并且 bufsz 不为零且不大于 RSIZE_MAX,则始终写入),如果 bufsz 被忽略,它将被写入缓冲区,如果运行时约束违反或编码错误发生,则为负值

代码例子
#include <cstdio>
#include <iostream>
#include <iomanip>

int main() {
  std::cout << std::setw(8) << std::left << "format" << std::setw(2) << "n" << " " << " string" << '\n';
  std::cout << std::setw(20) << std::setfill('-') << '-' << std::setfill(' ')<< std::endl;
  char buf[30] = {""};
  int n = sprintf(buf, "%d", 12345);
  std::cout << std::setw(8) << std::left << "%d:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%d", -12345);
  std::cout << std::setw(8) << std::left << "%d:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%x", 256);
  std::cout << std::setw(8) << std::left << "%x:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%o", 256);
  std::cout << std::setw(8) << std::left << "%o:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%f", 12.345);
  std::cout << std::setw(8) << std::left << "%f:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%.4f", 12.345);
  std::cout << std::setw(8) << std::left << "%.4f:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%.4f", 12.345);
  std::cout << std::setw(8) << std::left << "%.4f:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%e", 1234.5);
  std::cout << std::setw(8) << std::left << "%e:" << std::setw(2) << n << " " << buf << '\n';

  n = sprintf(buf, "%.4a", 147.0);
  std::cout << std::setw(8) << std::left << "%.4a:" << std::setw(2) << n << " " << buf << '\n';
}
代码输出结果
format  n   string
--------------------
%d:     5  12345
%d:     6  -12345
%x:     3  100
%o:     3  400
%f:     9  12.345000
%.4f:   7  12.3450
%.4f:   7  12.3450
%e:     12 1.234500e+03
%.4a:   11 0x1.2600p+7

to_chars

函数原型
#include <charconv>

struct to_chars_result {
    char* ptr;
    std::errc ec;
};

enum class chars_format {
    scientific = /*unspecified*/,
    fixed = /*unspecified*/,
    hex = /*unspecified*/,
    general = fixed | scientific
};

std::to_chars_result to_chars(char* first, char* last,/*see below*/ value, int base = 10);
std::to_chars_result to_chars(char*, char*, bool, int = 10) = delete;

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);
说明

value 值填充范围到[first, last) 指向的字符串,其中 [first, last) 必须是有效范围

返回
  • 成功时,返回 to_chars_result 类型的值,其中 ec 等于值初始化的 std::errcptr 是写入字符结尾的后一个指针。请注意,该字符串不是以 NUL 结尾的
  • 出错时,返回 to_chars_result 类型的值,其中 ec 等于 std::errc::value_too_large
代码例子
#include <iostream>
#include <charconv>
#include <string_view>
#include <iomanip>
#include <string>

template<typename T>
void print(T value, std::string_view str) {
  std::cout << "std::to_chars(" << std::setw(15) << std::right << std::setprecision(12) << value << ") = [" << str << "]\n";
}

template<typename T>
void test_integer(std::string& str, T value, int base = 10) {
  auto[p, ec] = std::to_chars(str.data(), str.data() + str.size(), value, base);
  if (ec == std::errc()) {
    print(value, std::string_view(str.data(), p - str.data()));
  } else if (ec == std::errc::value_too_large) {
    print(value, str);
  }
}

template<typename T>
void test_float(std::string& str, T value, std::chars_format fmt = std::chars_format::general) {
  auto[p, ec] = std::to_chars(str.data(), str.data() + str.size(), value, fmt);
  if (ec == std::errc()) {
    print(value, std::string_view(str.data(), p - str.data()));
  } else if (ec == std::errc::value_too_large) {
    print(value, str);
  }
}

template<typename T>
void test_float_precision(std::string& str, T value, std::chars_format fmt = std::chars_format::general, int precision = 6) {
  auto[p, ec] = std::to_chars(str.data(), str.data() + str.size(), value, fmt, precision);
  if (ec == std::errc()) {
    print(value, std::string_view(str.data(), p - str.data()));
  } else if (ec == std::errc::value_too_large) {
    print(value, str);
  }
}

int main()
{
  std::string str;
  str.resize(20);

  test_integer(str, 12345);
  test_integer(str, -12345);
  test_integer(str, 100, 8);

  test_float(str, 123.456789123);
  test_float_precision(str, 123.456789123, std::chars_format::general, 6);
  test_float(str, -123.456789123);
  test_float(str, 1234.5);
  test_float(str, 18.375, std::chars_format::hex);
  test_float(str, 147.0, std::chars_format::hex);
}
代码输出结果
format  n   string
--------------------
%d:     5  12345
%d:     6  -12345
%x:     3  100
%o:     3  400
%f:     9  12.345000
%.4f:   7  12.3450
%.4f:   7  12.3450
%e:     12 1.234500e+03
%.4a:   11 0x1.2600p+7
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,可以使用以下方法将字符串转换数字: 1. 使用库函数atoi():这个函数可以将字符串转换为整数。例如: ```c char str[] = "123"; int num = atoi(str); ``` 这样就将字符串"123"转换为整数123。 2. 使用库函数atof():这个函数可以将字符串转换为浮点数。例如: ```c char str[] = "3.14"; float num = atof(str); ``` 这样就将字符串"3.14"转换为浮点数3.14。 3. 使用库函数sscanf():这个函数可以根据指定的格式将字符串转换为特定类型的数据。例如: ```c char str[] = "456"; int num; sscanf(str, "%d", &num); ``` 这样就将字符串"456"转换为整数456,并存储在变量num中。 4. 使用库函数strtol():这个函数可以将字符串转换为长整数。例如: ```c char str[] = "789"; long num = strtol(str, NULL, 10); ``` 这样就将字符串"789"转换为长整数789。 以上是C语言中将字符串转换数字的几种常用方法。你可以根据需要选择合适的方法进行转换。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++ 字符串数字之间的相互转换](https://blog.csdn.net/weixin_43390123/article/details/116094291)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [C++中将字符串转换数字](https://blog.csdn.net/qq_46906413/article/details/122824849)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值