C++中将整数转换为字符串的替代方法是什么?

159

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


基本上是这个问题的相反。https://dev59.com/aHVC5IYBdhLWcg3wvTxa 答案是一样的。 - Martin York
16
以下是一些示例,可参考此链接:http://www.codeproject.com/KB/recipes/Tokenizer.aspx。它们非常高效且有些优雅。 - Matthieu N.
1
你可以在这里看到一个基准测试,比较了三种现代C++将整数转换为字符串的方法。 - Nikos Athanasiou
我在C语言中有同样的函数需求。我相信你可以想出如何在C++中进行封装。它是线程安全的,并处理所有正数、负数32位整数和零。性能非常优秀,算法精简,因此不会占用太多缓存。Ben Voigt有一种更快的方法,但它不是轻量级算法,所以除非你要做数十亿次这样的操作,否则可能过于复杂。 - user1899861
18个回答

195

1
很遗憾,Windows CE衍生平台默认没有iostreams。解决这个问题的方法是最好使用_itoa <>系列。 - Johann Gerell
1
你如何清除 stringstream? - Tomek
(对于非C++11)还有boost::to_string http://www.boost.org/doc/libs/1_51_0/boost/exception/to_string.hpp - alfC
@Jay 你可以在这里看到一个基准测试,比较了三种现代C++将整数转换为字符串的方法,并且其中一个答案涉及到使用stringstream时常见的错误。 - Nikos Athanasiou
@NikosAthanasiou 很好的参考,谢谢。它没有提到生成的可执行文件的大小。我曾经看到gcc向可执行文件中添加了数兆字节的未使用代码。 - Jay
显示剩余3条评论

56

boost::lexical_cast 的效果非常好。

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

26
使用Boost库进行单个类型转换。 :( - Chad Stewart
22
但如果你已经在使用Boost,那么这是免费的。 - Chris K
12
boost::lexical_cast 的速度非常缓慢。如果性能很重要,请勿使用它。 - Matthieu N.
10
在大多数情况下,我认为担心这个是过早优化。除非我的性能分析器告诉我否则,否则这不会阻止我使用它。 - Leon Timmermans
15
异常缓慢?你从哪里听来的?它的实际表现相当不错!http://www.boost.org/doc/libs/1_49_0/doc/html/boost_lexical_cast/performance.html - kralyk
显示剩余2条评论

51

考古学

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

C语言方式

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

尽管某些函数不在标准中,如“onebyone”在其中一条评论中所提到的那样,但大多数编译器都会为您提供替代方案(例如Visual C ++有自己的_snprintf,如果需要,可以将其typedef为snprintf)。

C ++方式

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

结论

您正在使用C ++,这意味着您可以选择想要的方式:

  • 更快的方式(即C的方式),但您应该确保代码是应用程序的瓶颈(过早的优化是有害的等等),并且您的代码是安全地封装以避免风险Buffer overruns。

  • 更安全的方式(即C ++的方式),如果您知道此代码部分不是关键性的,则最好确保此代码部分不会在随机时刻中断,因为有人误解了大小或指针(在现实生活中发生,像...昨天,在我的电脑上,因为有人认为它“酷”而使用了更快的方式,而没有真正需要它)。


3
@Chris Kaminski:我的测试表明,sprintf的速度比其他方法快了5到10倍,这也得到了Herb Sutter自己的证实。如果您有不同结果的测试,请告诉我。 - paercebal
3
如果你学习C++的流接口,你就会明白它们为什么会更慢,即使只输出一个简单的整数:在C中,你使用自己的缓冲区,可能分配在栈中,而在C++中,stringstream将使用它自己的缓冲区。在C中,你可以重用自己的缓冲区,在C++中,你必须从stringstream中提取字符串,这会产生一个std::string的副本。 - paercebal
2
@fuzzyTew:谢谢你的关心,但我认为我足够熟悉C API和C++ API来处理sprintf,并知道何时(以及如何)安全地使用它,以及何时根本不使用它... :-D - paercebal
2
@fuzzyTew:1 在我的帖子中,我提到了sprintf及其安全变体,而不仅仅是sprintf。2 知道你的代码在哪里编译并不是一项不可能完成的任务(在我这种情况下,最差的情况是Windows/VC++、Solaris/CC和Linux/g++,最好的情况是仅限于Windows/VC++)。3 你所描述的世界是试图破坏你的代码的破坏者成为了常态。我的世界由普通开发人员组成,因此花费时间通过重写每个API的“安全”版本来保护我的代码免受破坏者攻击是没有生产力的。[...] - paercebal
2
@fuzzyTew: [...] 结论 使用手头最好的工具。如果最好的工具是隐藏在包装类或函数中的sprintf……现在,如果你主张将sprintf重写作为这个问题的答案,请随意编写你自己的答案。我不确定问题的作者是否会阅读所有的评论。 - paercebal
显示剩余10条评论

39

尝试使用sprintf():

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

sprintf() 函数类似于 printf(),但输出字符串。

此外,正如 Parappa 在评论中提到的那样,您可能需要使用 snprintf() 来防止缓冲区溢出(发生在您要转换的数字不适合您字符串大小的情况下)。它的工作原理如下:

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

8
sprintf() 不是 C++ 的函数,而是 C 的函数。 - OJ.
11
为避免缓冲区溢出,建议使用snprintf()函数。在以上示例中,只需要进行一行修改:snprintf(str, sizeof(str), "%d", num); - Parappa
2
在我看来,字符串流可能是更好的选择。 - mdec
2
OJ:sprintf 也是 C++ 的……大多数 C 的东西在 C++ 中都可以使用。这不是偶然的。C++ 的初衷是作为 C++ 的“层”而存在,而不是像它现在(可能过度)成为的定义性架构。 - Erik Aronesty
函数sprintf中的str类型应该是“string”,而不是“str”。 - Xb74Dkjb

20

在幕后,lexical_cast 实际上是这样实现的:

std::stringstream str;
str << myint;
std::string result;
str >> result;
如果您不想为此引入boost,则使用上述方法是一个很好的解决方案。

我怀疑当str.str()就足够时,它是否会流入字符串中。 - sbi
1
如果lexical_cast可以做到这一点,那么如何解释性能上的巨大差距呢? - Nikos Athanasiou
他没有在你链接的问题中解释每次创建stringstream对象的原因吗? - 1800 INFORMATION

13

我们可以在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 <string>


13

C++11最终提供了解决方案,提供了std::to_string。对于老的编译器来说,boost::lexical_cast也是一个方便的工具。


9
我使用这些模板。
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;
}

这些很好,但遗憾的是缺少错误处理。 - sbi

7

请尝试使用高质量的C++库Boost.FormatFastFormat

int i = 10;
std::string result;

使用Boost.Format

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

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

显然,它们的功能不仅仅是简单地转换一个整数。

6

通过一个聪明地编写的模板函数,您可以将任何内容转换为字符串。此代码示例使用循环在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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接