如何在 C++ 中将数字转换为字符串,反之亦然

Posted

技术标签:

【中文标题】如何在 C++ 中将数字转换为字符串,反之亦然【英文标题】:How to convert a number to string and vice versa in C++ 【发布时间】:2011-07-14 11:44:22 【问题描述】:

由于这个问题每周都会被问到,这个FAQ 可能会帮助很多用户。

如何在 C++ 中将整数转换为字符串

如何在 C++ 中将字符串转换为整数

如何在 C++ 中将浮点数转换为字符串

如何在 C++ 中将字符串转换为浮点数

【问题讨论】:

对于这样的转换,我有一个书签converttypes.com 【参考方案1】:

C++11 更新

C++11 标准开始,字符串到数字的转换(反之亦然)已内置到标准库中。 <string> 中包含以下所有功能(根据第 21.5 段)。

字符串转数字

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

每个都将字符串作为输入,并尝试将其转换为数字。如果无法构造有效数字,例如因为没有数字数据或数字超出类型的范围,则会引发异常(std::invalid_argumentstd::out_of_range)。

如果转换成功并且idx 不是0idx 将包含第一个未用于解码的字符的索引。这可能是最后一个字符后面的索引。

最后,整数类型允许指定一个基数,对于大于 9 的数字,假定为字母表(a=10 直到 z=35)。您可以在此处找到有关可以为 floating-point numbers、signed integers 和 unsigned integers 解析的确切格式的更多信息。

最后,对于每个函数,还有一个重载接受 std::wstring 作为它的第一个参数。

数字转字符串

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

这些更直接,您传递适当的数字类型并返回一个字符串。对于格式化选项,您应该返回 C++03 stringsream 选项并使用流操纵器,如此处的另一个答案中所述。

如 cmets 中所述,这些函数回退到可能不是最大精度的默认尾数精度。如果您的应用程序需要更高的精度,最好还是回到其他字符串格式化程序。

还定义了类似的函数,命名为to_wstring,它们将返回std::wstring

【讨论】:

std::to_string 在浮点类型上损失了很多精度。例如double f = 23.4323897462387526; std::string f_str = std::to_string(f); 返回一个字符串 23.432390。这使得使用这些函数无法往返浮点值。 @fun4jimmy 这是标准施加的限制还是特定于实现的限制?将其添加到答案中。并不是说通过字符串进行往返浮动是一个好主意。 C++ 标准说“返回:每个函数返回一个字符串对象,该对象保存其参数值的字符表示形式,该参数值将通过调用 sprintf(buf, fmt, val) 生成格式说明符为 "%d""%u""%ld""%lu"“%lld”“%llu”“%f”“%f” , 或 "%Lf",其中buf 指定一个足够大的内部字符缓冲区。" 我查看了 C99 标准printf 我认为小数位数取决于 float.h 中的#define DECIMAL_DIG Bruce Dawson 在他的blog 上有一些关于往返浮点数需要什么精度的好文章。 所有这些函数都受全局语言环境的影响,如果您使用库,尤其是使用线程时,这可能会导致问题。在这里查看我的问题:***.com/questions/31977457/…【参考方案2】:

如何在 C++03 中将数字转换为字符串

    不要使用 itoaitof 函数,因为它们是非标准的,因此不可移植。

    使用字符串流

     #include <sstream>  //include this to use string streams
     #include <string> 
    
    int main()
        
        int number = 1234;
    
        std::ostringstream ostr; //output string stream
        ostr << number; //use the string stream just like cout,
        //except the stream prints not to stdout but to a string.
    
        std::string theNumberString = ostr.str(); //the str() function of the stream 
        //returns the string.
    
        //now  theNumberString is "1234"  
    
    

    请注意,您还可以使用字符串流将浮点数转换为字符串,还可以根据需要格式化字符串,就像 cout 一样

    std::ostringstream ostr;
    float f = 1.2;
    int i = 3;
    ostr << f << " + " i << " = " << f + i;   
    std::string s = ostr.str();
    //now s is "1.2 + 3 = 4.2" 
    

    您可以对字符串流使用流操作符,例如std::endlstd::hex 和函数std::setw()std::setprecision() 等,方式与cout 完全相同

    不要混淆 std::ostringstreamstd::ostrstream。后者已弃用

    使用boost lexical cast。如果你对 boost 不熟悉,最好从一个像 lexical_cast 这样的小库开始。下载并安装 boost 及其文档go here。尽管 boost 不在 C++ 标准中,但许多 boost 库最终都会标准化,并且 boost 被广泛认为是最好的 C++ 库。

    词法转换在底层使用流,所以这个选项基本上和前一个相同,只是不那么冗长。

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    
       float f = 1.2;
       int i = 42;
       std::string sf = boost::lexical_cast<std::string>(f); //sf is "1.2"
       std::string si = boost::lexical_cast<std::string>(i); //sf is "42"
    
    

如何在 C++03 中将字符串转换为数字

    从 C 继承的最轻量级的选项是函数 atoi(用于整数(从字母到整数))和 atof(用于浮点值(从字母到浮点))。这些函数将 C 风格的字符串作为参数 (const char *),因此它们的使用可能被认为不是很好的 C++ 实践。 cplusplus.com 有关于atoi 和atof 的易于理解的文档,包括它们在输入错误时的行为方式。但是,链接包含一个错误,根据标准,如果输入数字太大而无法适应目标类型,则行为未定义。

    #include <cstdlib> //the standard C library header
    #include <string>
    int main()
    
        std::string si = "12";
        std::string sf = "1.2";
        int i = atoi(si.c_str()); //the c_str() function "converts" 
        double f = atof(sf.c_str()); //std::string to const char*
    
    

    使用字符串流(这次输入字符串流,istringstream)。同样,istringstream 的使用方式与cin 一样。同样,不要将istringstreamistrstream 混淆。后者已被弃用。

    #include <sstream>
    #include <string>
    int main()
    
       std::string inputString = "1234 12.3 44";
       std::istringstream istr(inputString);
       int i1, i2;
       float f;
       istr >> i1 >> f >> i2;
       //i1 is 1234, f is 12.3, i2 is 44  
    
    

    使用boost lexical cast。

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    
       std::string sf = "42.2"; 
       std::string si = "42";
       float f = boost::lexical_cast<float>(sf); //f is 42.2
       int i = boost::lexical_cast<int>(si);  //i is 42
           
    

    如果输入错误,lexical_cast 会抛出 boost::bad_lexical_cast 类型的异常

【讨论】:

atoi 的 cplusplus 文档不是很好,是不正确的。它没有提到如果字符串的数值不能在int 中表示,那么行为是未定义的。相反,它表示超出范围的值被限制为INT_MAX/INT_MIN,我在 C++03 或 C89 中都找不到。对于不受信任/未经验证的输入,或者在处理流不支持的基础时,您需要strtol,它已定义错误行为。以及atof/strtod 的类似 cmets。 cplusplus.com 关于“atoi”的错误。它说关于返回值“如果无法执行有效的转换,则返回零值。如果正确的值超出可表示值的范围,则返回 INT_MAX 或 INT_MIN。”,但规范说“如果结果的值无法表示,行为未定义。”并且“除了错误行为外,它们等效于(int)strtol(nptr, (char **)NULL, 10)。 atoi[...] 函数返回转换后的值。”。众所周知,cplusplus.com 对于初学者来说是一个非常糟糕的信息来源。 istr &gt;&gt; i1 &gt;&gt; f &gt;&gt; i2; 严重错过了成功检查。 可能要加std::to_string @ArmenTsirunyan:从我的角度+10,这是我见过的最好的答案之一。谢谢你的回答。【参考方案3】:

在 C++17 中,新函数 std::to_chars 和 std::from_chars 在标题 charconv 中引入。

std::to_chars 独立于语言环境,不分配, 并且不投掷。

只有一小部分格式政策使用 提供了其他库(例如 std::sprintf)。

来自std::to_chars,同样来自std::from_chars。

std::from_chars 可以恢复的保证 每个浮点值格式化 仅当两者都提供时才提供 by to_chars exactly 函数来自相同的实现

 // See en.cppreference.com for more information, including format control.
#include <cstdio>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <charconv>

using Type =  /* Any fundamental type */ ;
std::size_t buffer_size = /* ... */ ;

[[noreturn]] void report_and_exit(int ret, const char *output) noexcept 

    std::printf("%s\n", output);
    std::exit(ret);

void check(const std::errc &ec) noexcept

    if (ec ==  std::errc::value_too_large)
        report_and_exit(1, "Failed");

int main() 
    char buffer[buffer_size];        
    Type val_to_be_converted, result_of_converted_back;

    auto result1 = std::to_chars(buffer, buffer + buffer_size,  val_to_be_converted);
    check(result1.ec);
    *result1.ptr = '\0';

    auto result2 = std::from_chars(buffer, result1.ptr, result_of_converted_back);
    check(result2.ec);

    assert(val_to_be_converted == result_of_converted_back);
    report_and_exit(0, buffer);

虽然编译器没有完全实现,但肯定会实现的。

【讨论】:

【参考方案4】:

我从 *** 的某个地方偷了这个方便的类,以将任何可流式传输的内容转换为字符串:

// make_string
class make_string 
public:
  template <typename T>
  make_string& operator<<( T const & val ) 
    buffer_ << val;
    return *this;
  
  operator std::string() const 
    return buffer_.str();
  
private:
  std::ostringstream buffer_;
;

然后你把它当作;

string str = make_string() << 6 << 8 << "hello";

相当漂亮!

我还使用此函数将字符串转换为可流式传输的任何内容,尽管如果您尝试解析不包含数字的字符串,它不是很安全; (也没有最后一个聪明)

// parse_string
template <typename RETURN_TYPE, typename STRING_TYPE>
RETURN_TYPE parse_string(const STRING_TYPE& str) 
  std::stringstream buf;
  buf << str;
  RETURN_TYPE val;
  buf >> val;
  return val;

用作:

int x = parse_string<int>("78");

您可能还需要 wstrings 的版本。

【讨论】:

这正是 boost::lexical_cast 所做的。而 boost 则以更通用的方式进行。 没错,我浏览了第一个答案并没有看到 boost::lexical_casts。【参考方案5】:
#include <iostream>
#include <string.h>
using namespace std;
int main() 
   string s="000101";
   cout<<s<<"\n";
   int a = stoi(s);
   cout<<a<<"\n";
   s=to_string(a);
   s+='1';
   cout<<s;
   return 0;

输出:

000101 101 1011

【讨论】:

您好,答案不完整(没有浮点转换)并且也不正确(to_string 未定义)。请务必提供有用的答案

以上是关于如何在 C++ 中将数字转换为字符串,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中将 Int 转换为 String,反之亦然(不使用像 sstream 这样的库)

在 C++ 中将数字转换为字符串的最佳方法? [复制]

新网站在数字类型输入中将十进制逗号转换为 ~ 点,反之亦然。该浏览器功能的 Javascript 名称?

如何在 C++ 中将十六进制数字转换为二进制?

如何在 C++ 中将大数字符串转换为整数?

如何在 C++ 中将字符串转换为双精度值?