【问题标题】:Alternative to itoa() for converting integer to string C++? [duplicate]替代 itoa() 将整数转换为字符串 C++? [复制]
【发布时间】:2010-09-18 16:27:13
【问题描述】:

我想知道是否有替代 itoa() 将整数转换为字符串的方法,因为当我在 Visual Studio 中运行它时会收到警告,而当我尝试在 Linux 下构建程序时,会出现编译错误.

【问题讨论】:

  • 基本上是这个问题的反面。 stackoverflow.com/questions/200090/… 答案是一样的。
  • 下面的一些例子怎么样:codeproject.com/KB/recipes/Tokenizer.aspx 它们非常高效而且有点优雅。
  • 你可以看到 here 一个比较 3 种现代 C+ 将整数转换为字符串的方法的基准
  • 我对 C 中的函数有相同的要求。我相信您可以弄清楚如何用 C++ 进行包装。它是线程安全的,可以处理所有正、负 32 位整数和零。性能卓越,算法精简,因此不会占用大量缓存。 Ben Voigt 有一个更快的方法,但它不是一个轻量级算法,所以除非你做数十亿次这样的事情,否则它可能有点矫枉过正。

标签: c++ integer stdstring itoa


【解决方案1】:

如果您对快速且安全的整数到字符串的转换方法感兴趣并且不限于标准库,我可以推荐{fmt} 库中的format_int 方法:

fmt::format_int(42).str();   // convert to std::string
fmt::format_int(42).c_str(); // convert and get as a C string
                             // (mind the lifetime, same as std::string::c_str())

根据 Boost Karma 的 integer to string conversion benchmarks,这种方法比 glibc 的 sprintfstd::stringstream 快几倍。它甚至比 Boost Karma 自己的 int_generator 还要快,正如 independent benchmark 所证实的那样。

免责声明:我是这个库的作者。

【讨论】:

    【解决方案2】:

    С++11 最终解决了这个问题,提供std::to_stringboost::lexical_cast 也是旧编译器的便捷工具。

    【讨论】:

      【解决方案3】:

      最好的答案,IMO,是这里提供的函数:

      http://www.jb.man.ac.uk/~slowe/cpp/itoa.html

      它模仿了许多库提供的非 ANSI 函数。

      char* itoa(int value, char* result, int base);
      

      它也非常快并且在 -O3 下优化得很好,而你不使用 c++ string_format() ... 或 sprintf 的原因是它们太慢了,对吧?

      【讨论】:

      • 这是完全回答问题的唯一答案。 C++ to_string() 方法不能复制 C 的 itoa 的全部功能,因为它不能处理任意基数。为什么不包含此功能有点令人困惑,特别是考虑到反函数 stoi() 可以处理任意基数。
      • 更新链接(同一篇文章):strudel.org.uk/itoa
      【解决方案4】:

      我前段时间写了这个线程安全函数,对结果非常满意,感觉算法轻量级和精简,性能大约是标准 MSVC _itoa() 函数的 3 倍.

      这是链接。 Optimal Base-10 only itoa() function? 性能至少是 sprintf() 的 10 倍。基准测试也是函数的 QA 测试,如下所示。

      start = clock();
      for (int i = LONG_MIN; i < LONG_MAX; i++) {
          if (i != atoi(_i32toa(buff, (int32_t)i))) {
              printf("\nError for %i", i);
          }
          if (!i) printf("\nAt zero");
      }
      printf("\nElapsed time was %f milliseconds", (double)clock() - (double)(start));
      

      关于使用调用者的存储提出了一些愚蠢的建议,这会使结果浮动在调用者地址空间的缓冲区中的某个位置。别理他们。正如基准/QA 代码所示,我列出的代码运行良好。

      我相信这段代码足够精简,可以在嵌入式环境中使用。当然是 YMMV。

      【讨论】:

        【解决方案5】:

        在 C++11 中你可以使用std::to_string:

        #include <string>
        
        std::string s = std::to_string(5);
        

        如果您使用的是 C++11 之前的版本,则可以使用 C++ 流:

        #include <sstream>
        
        int i = 5;
        std::string s;
        std::stringstream out;
        out << i;
        s = out.str();
        

        取自http://notfaq.wordpress.com/2006/08/30/c-convert-int-to-string/

        【讨论】:

        【解决方案6】:

        我们可以在c++中定义自己的iota函数为:

        string itoa(int a)
        {
            string ss="";   //create empty string
            while(a)
            {
                int x=a%10;
                a/=10;
                char i='0';
                i=i+x;
                ss=i+ss;      //append new character at the front of the string!
            }
            return ss;
        }
        

        别忘了#include &lt;string&gt;

        【讨论】:

          【解决方案7】:

          我使用这些模板

          template <typename T> string toStr(T tmp)
          {
              ostringstream out;
              out << tmp;
              return out.str();
          }
          
          
          template <typename T> T strTo(string tmp)
          {
              T output;
              istringstream in(tmp);
              in >> output;
              return output;
          }
          

          【讨论】:

          • 这些很好,但不幸的是缺乏错误处理。
          【解决方案8】:
          int number = 123;
          
          stringstream = s;
          
          s << number;
          
          cout << ss.str() << endl;
          

          【讨论】:

            【解决方案9】:

            您实际上可以使用一个巧妙编写的模板函数将任何内容转换为字符串。此代码示例使用循环在 Win-32 系统中创建子目录。字符串连接运算符 operator+ 用于连接根与后缀以生成目录名称。后缀是通过使用模板函数将循环控制变量 i 转换为 C++ 字符串并将其与另一个字符串连接来创建的。

            //Mark Renslow, Globe University, Minnesota School of Business, Utah Career College
            //C++ instructor and Network Dean of Information Technology
            
            #include <cstdlib>
            #include <iostream>
            #include <string>
            #include <sstream> // string stream
            #include <direct.h>
            
            using namespace std;
            
            string intToString(int x)
            {
            /**************************************/
            /* This function is similar to itoa() */
            /* "integer to alpha", a non-standard */
            /* C language function. It takes an   */
            /* integer as input and as output,    */
            /* returns a C++ string.              */
            /* itoa()  returned a C-string (null- */
            /* terminated)                        */
            /* This function is not needed because*/
            /* the following template function    */
            /* does it all                        */
            /**************************************/   
                   string r;
                   stringstream s;
            
                   s << x;
                   r = s.str();
            
                   return r;
            
            }
            
            template <class T>
            string toString( T argument)
            {
            /**************************************/
            /* This template shows the power of   */
            /* C++ templates. This function will  */
            /* convert anything to a string!      */
            /* Precondition:                      */
            /* operator<< is defined for type T    */
            /**************************************/
                   string r;
                   stringstream s;
            
                   s << argument;
                   r = s.str();
            
                   return r;
            
            }
            
            int main( )
            {
                string s;
            
                cout << "What directory would you like me to make?";
            
                cin >> s;
            
                try
                {
                  mkdir(s.c_str());
                }
                catch (exception& e) 
                {
                  cerr << e.what( ) << endl;
                }
            
                chdir(s.c_str());
            
                //Using a loop and string concatenation to make several sub-directories
                for(int i = 0; i < 10; i++)
                {
                    s = "Dir_";
                    s = s + toString(i);
                    mkdir(s.c_str());
                }
                system("PAUSE");
                return EXIT_SUCCESS;
            }
            

            【讨论】:

              【解决方案10】:

              试试Boost.FormatFastFormat,这两个都是高质量的 C++ 库:

              int i = 10;
              std::string result;
              

              使用 Boost.Format

              result = str(boost::format("%1%", i));
              

              或快速格式化

              fastformat::fmt(result, "{0}", i);
              fastformat::write(result, i);
              

              显然,它们都不仅仅是一个整数的简单转换

              【讨论】:

                【解决方案11】:

                在 Windows CE 衍生平台上,默认情况下没有 iostreams。去那里的方法是使用_itoa&lt;&gt; 家族,通常是_itow&lt;&gt;(因为大多数字符串都是Unicode)。

                【讨论】:

                  【解决方案12】:

                  考古

                  itoa 是一个非标准辅助函数,旨在补充 atoi 标准函数,并且可能隐藏了一个 sprintf(它的大部分功能都可以用 sprintf 来实现):http://www.cplusplus.com/reference/clibrary/cstdlib/itoa.html

                  C 方式

                  使用 sprintf。或 snprintf。或者你找到的任何工具。

                  尽管有些函数不在标准中,正如“onebyone”在他的一个 cmets 中正确提到的那样,大多数编译器都会为您提供替代方案(例如,Visual C++ 有自己的 _snprintf,如果需要,您可以 typedef 到 snprintf它)。

                  C++ 方式。

                  使用 C++ 流(在当前情况下为 std::stringstream(甚至是已弃用的 std::strstream,正如 Herb Sutter 在他的一本书中提出的那样,因为它更快一些)。

                  结论

                  你在 C++ 中,这意味着你可以选择你想要的方式:

                  • 更快的方式(即 C 方式),但您应该确保代码是您的应用程序中的瓶颈(过早的优化是邪恶的,等等)并且您的代码被安全地封装以避免出现缓冲区溢出的风险。

                  • 更安全的方式(即 C++ 方式),如果您知道这部分代码并不重要,那么最好确保这部分代码不会因为有人弄错大小或指针而随机中断(这发生在现实生活中,比如......昨天,在我的电脑上,因为有人认为在不需要它的情况下使用更快的方式“很酷”)。

                  【讨论】:

                  • @Chris Kaminski:我的一次测试确实显示 sprintf 快了 5 到 10 倍,这证实了我的 Herb Sutter 自己的测量结果。如果您有不同结果的测试,我很感兴趣。
                  • @Chris Kaminski:如果你研究了 c++ 流的接口,你就会明白为什么它们更慢,即使输出一个简单的整数:在 C 中,你使用自己的缓冲区,可能分配在堆栈中,而在 C++ 中,字符串流将使用它自己的。在 C 中,您可以重用缓冲区。在 C++ 中,您必须从 stringstream 中提取字符串,这是一个 std::string 副本。
                  • @fuzzyTew :感谢您的关注,但我想我对 C API 和 C++ API 都足够熟悉来处理 sprintf,并且知道何时(以及如何)安全使用它,何时不使用完全使用它... :-D
                  • @fuzzyTew: 1 在我的帖子中,我谈到了 sprintf 及其安全变体,而不仅仅是 sprintf。 2 知道你的代码在哪里编译不是一项不可能完成的任务(在我的情况下,最坏的情况是 Windows/VC++、Solaris/CC 和 Linux/g++,最好的情况是仅 Windows/VC++)。 3您正在描述一个破坏者试图使您的代码崩溃的世界是常态。我的世界是由普通开发人员组成的,因此浪费时间试图通过重写我的每个 API 的“安全”版本来保护我的代码免受破坏者是没有效率的。 [...]
                  • @fuzzyTew: [...] Conclusion 使用手头最好的工具。如果最好的工具是隐藏在包装类或函数中的 sprintf... 现在,如果您主张重写 sprintf 作为该问题的答案,请随意编写您自己的答案。我不确定问题作者是否阅读了所有 cmets。
                  【解决方案13】:

                  请注意,所有stringstream 方法可能涉及锁定使用区域设置对象进行格式化。如果您从多个线程中使用此转换,则可能需要注意...

                  请参阅此处了解更多信息。 Convert a number to a string with specified length in C++

                  【讨论】:

                    【解决方案14】:

                    试试 sprintf():

                    char str[12];
                    int num = 3;
                    sprintf(str, "%d", num); // str now contains "3"
                    

                    sprintf() 与 printf() 类似,但输出为字符串。

                    此外,正如 Parappa 在 cmets 中提到的,您可能希望使用 snprintf() 来阻止发生缓冲区溢出(您正在转换的数字不适合您的字符串的大小。)它的工作原理是这样的:

                    snprintf(str, sizeof(str), "%d", num);
                    

                    【讨论】:

                    • sprintf() 不是 C++。是 C。
                    • 您应该使用 snprintf() 来避免缓冲区溢出。在上面的例子中只改变了一行:snprintf(str, sizeof(str), "%d", num);
                    • 恕我直言 Stringstreams 会是更好的选择。
                    • OJ: sprintf 也是 c++ ......大多数 C 的东西都在 c++ 中工作。这不是意外。 c++ 旨在成为 c++ 之上的“层”......而不是像它(可能是错误的)那样定义架构
                    • 函数中str的类型:sprintf是'str',但question应该是'string'。
                    【解决方案15】:

                    在幕后,lexical_cast 是这样做的:

                    std::stringstream str;
                    str << myint;
                    std::string result;
                    str >> result;
                    

                    如果您不想为此“拖入”提升,那么使用上述方法是一个很好的解决方案。

                    【讨论】:

                    • 我怀疑当str.str() 足够时它会流入字符串。
                    • 如果 lexical_cast 这样做,performance 中的大差距如何解释?
                    • 他不是在你链接的问题中解释说是由于每次都创建字符串流对象吗?
                    【解决方案16】:

                    从技术上讲,上述大多数建议都不是 C++,而是 C 解决方案。

                    查看std::stringstream的用法。

                    【讨论】:

                    • @OJ:“技术上不是 C++”-这是挑剔的(并且进一步挑剔,因为有人提到它们中的大多数在技术上都是 C++),特别是因为 OP 正在寻找无警告替换 itoa()。
                    【解决方案17】:

                    分配一个足够长的字符串,然后使用snprintf。

                    【讨论】:

                      【解决方案18】:

                      boost::lexical_cast 效果很好。

                      #include <boost/lexical_cast.hpp>
                      int main(int argc, char** argv) {
                          std::string foo = boost::lexical_cast<std::string>(argc);
                      }
                      

                      【讨论】:

                      • 使用 Boost 库进行单次转换。 :(
                      • 但如果你已经在使用 Boost,它是免费赠品。
                      • boost::lexical_cast 非常缓慢。如果性能很重要,请不要使用它。
                      • 我认为在大多数情况下担心这是过早的优化。除非我的分析器另有说明,否则它不会阻止我使用它。
                      • 慢得痛苦?你是在哪里拿到的?它实际上表现相当不错! boost.org/doc/libs/1_49_0/doc/html/boost_lexical_cast/…
                      猜你喜欢
                      • 1970-01-01
                      • 2012-03-30
                      • 2011-07-31
                      • 1970-01-01
                      • 2011-12-27
                      • 1970-01-01
                      • 2012-04-30
                      • 2012-08-16
                      相关资源
                      最近更新 更多