在C ++中将int转换为字符串的最简单方法


1573

从C ++ 转换int为等效的最简单方法是什么string。我知道两种方法。有没有更简单的方法?

(1)

int a = 10;
char *intStr = itoa(a);
string str = string(intStr);

(2)

int a = 10;
stringstream ss;
ss << a;
string str = ss.str();

4
我认为您提供的两种方法都是很好的解决方案。这取决于您需要执行此操作的上下文。如果您已经在使用流,例如读取或写入文件,则第二种方法是最好的。如果需要将int作为字符串传递给函数参数,则itoa可能是一种简单的方法。但是在大多数情况下,在处理文件时会发生从int到字符串的转换,因此流是适当的。
查尔斯·布鲁内

41
选项1甚至对您如何工作?我的理解itoa()需要三个参数。
b1nary.atr0phy 2013年

1
itoa将比同等速度更快。还有一些通过itoa方法重用字符串缓冲区的方法(如果您经常生成字符串(例如,为了快速更新数值输出,则避免堆分配)。另外,您可以生成一个自定义的streambuf来减少一些分配开销等。首先构造该流也不是一项低成本的尝试。
皮特

6
@Pete:一旦你开始担心这是更快,你会想看看stackoverflow.com/questions/4351371/...
本·福格特

20
请注意,itoa()不是标准的一部分,因此使用它会使您的代码不可移植,因为并非所有编译器都支持它。对于Linux,除非您使用的是GCC(不支持此功能)以外的其他工具,否则您肯定会出局。如果您使用的是C ++ 0x,请使用@Matthieu在他的答案中建议的内容。如果不是这种情况,请使用stringstream,因为它是受良好支持的功能,并且您的代码应该与那里的每个C ++编译器兼容。另外,您也可以始终使用sprintf()。
rbaleksandar 2014年

Answers:


2097

C ++ 11介绍std::stoi(并为每个数字型变体)和std::to_string,将C的对应物atoiitoa,但在用术语表达std::string

#include <string> 

std::string s = std::to_string(42);

因此,这是我能想到的最短的方法。您甚至可以省略使用auto关键字命名类型:

auto s = std::to_string(42);

注:参见[string.conversions] 21.5n3242


199
to_string不是的成员std修复:stackoverflow.com/questions/12975341/...

36
或者根据您的编译器,设置正确的语言标准:g++ -std=c++11 someFile.cc
Thomas M. DuBuisson

12
@Steve:应该是。它是std我所知道的每个编译器的成员,除了一个。
Mooing Duck,

5
@MatthiewM。我使用的是您建议的相同的东西,但我遇到此错误:Error : No instance of overloaded function "std::to_string" matches the argument list 我使用的是VS2010 c ++

19
@Flying:在VS2010下,您必须将转换后的整数显式转换为以下类型之一[_Longlong,_ULonglong,long double];即:string s = to_string((_ULonglong)i);
Zac 2013年

184

几年后,与@ v.oddou进行了讨论,C ++ 17终于提供了一种方法,可以解决原始的基于宏的类型不可知的解决方案(下面保留),而无需经历宏的丑陋。

// variadic template
template < typename... Args >
std::string sstr( Args &&... args )
{
    std::ostringstream sstr;
    // fold expression
    ( sstr << std::dec << ... << args );
    return sstr.str();
}

用法:

int i = 42;
std::string s = sstr( "i is: ", i );
puts( sstr( i ).c_str() );

Foo x( 42 );
throw std::runtime_error( sstr( "Foo is '", x, "', i is ", i ) );

原始答案:

由于“将...转换为字符串”是一个经常出现的问题,因此我总是在C ++源代码的中央标头中定义SSTR()宏:

#include <sstream>

#define SSTR( x ) static_cast< std::ostringstream & >( \
        ( std::ostringstream() << std::dec << x ) ).str()

用法尽可能简单:

int i = 42;
std::string s = SSTR( "i is: " << i );
puts( SSTR( i ).c_str() );

Foo x( 42 );
throw std::runtime_error( SSTR( "Foo is '" << x << "', i is " << i ) );

上面是C ++ 98兼容的(如果您不能使用C ++ 11 std::to_string),并且不需要任何第三方包含(如果您不能使用Boost lexical_cast<>);这些其他解决方案都具有更好的性能。


2
我不太熟悉,dynamic_cast但是我正在使用clang进行编译,因此它对此有所抱怨。如果我只是略过,dynamic_cast那它编译就很好。dynamic_cast在这种情况下服务的目的是什么?我们已经在创建一个ostringstream,那么为什么要投射它呢?
Mathew

2
@Mathew:我的答案中的链接指向该结构各部分的详细说明。当我们创建一个时ostringstream,我们对其进行了调用operator<<(),该方法会返回ostream &- .str()尚未定义。我真的很奇怪,如果不使用强制转换,c将如何使这项工作(或为什么它会产生错误)。这个结构已经在很多地方发布,并且我已经在包括MSVC,GCC和XLC在内的许多不同的编译器上使用了十多年,所以我很惊讶于此。
DevSolar 2014年

5
只是出于好奇而来参加聚会,并对此表示不满。原因:对于不雅观且可能很慢的解决方案,投票太多。1.宏用法。我并没有系统地皱眉任何宏,但是这个宏太短了,最终客户总是担心重复该争论,除了担心不受保护的多行宏。(不受do {} while(0)保护)2. dynamic_cast。似乎这里只需要static_cast,除非您想断言该库确实按照您的期望实现了。在这种情况下,您应该使用boost :: polymorphic_downcast。
v.oddou

2
@ v.oddou:当然,您可以自由地进行批判。但是1.是无效的-宏是单个语句,do { } while( 0 )不会添加任何内容。在2.和3.中,您可能有一个要点-可以使用静态强制转换完成,也许其中的一个模板向导可以提供一个“更细”的界面。但是正如我所说,这绝不是我的发明。环顾四周,这个宏(宏!)无处不在。POLA本身就是这种情况。我可能会对此加一点玩意,以使其更“简化”。
DevSolar

1
@ v.oddou:看看我在C ++ 17给我们带来的发现中发现了什么。:-)希望您喜欢最新的答案。
DevSolar

109

我通常使用以下方法:

#include <sstream>

template <typename T>
  std::string NumberToString ( T Number )
  {
     std::ostringstream ss;
     ss << Number;
     return ss.str();
  }

进行详细说明。


2
使用之前ss,您需ss.clear()要这样做。没有这种初始化,我已经看到了意想不到的结果。
lifebalance 2015年

14
@lifebalance:我从未见过这种行为。
Rasoul

18
@lifebalance:您不需要clear()新建的ostringstream对象。clear()重置错误/错误标志,并且尚未生成任何错误/错误条件。
人头马(Remy Lebeau)2015年

2
@Rasoul NumberToString(23213.123)产生,23213.1std::to_string(23213.123)产生23213.123000时在那里发生什么?
Killzone Kid

1
@KillzoneKid这是因为std'ostream是有状态的(这意味着任何以前的状态更改都将保留,例如十进制数字),而此方法以默认状态开始。
xryl669

85

最常见的简单方法大概就是将您的第二选择包装到名为的模板中lexical_cast,例如Boost中的模板,因此您的代码如下所示:

int a = 10;
string s = lexical_cast<string>(a);

这样的好处之一是它也支持其他类型的转换(例如,相反方向的效果也一样)。

还要注意,尽管Boost lexical_cast刚开始只是写到一个字符串流,然后从该流中提取回来,但它现在有几个附加项。首先,已经添加了许多类型的专门化,因此对于许多常见类型,它比使用stringstream的速度快得多。其次,它现在检查结果,因此(例如)如果您从字符串转换为int,则如果该字符串包含无法转换为的内容int(例如,1234将成功但123abc会抛出),则可能引发异常。

从C ++ 11开始,有一个std::to_string针对整数类型重载的函数,因此您可以使用如下代码:

int a = 20;
std::string s = std::to_string(a);
// or: auto s = std::to_string(a);

这些标准定义为等同于在做与转换sprintf(使用所提供的类型的对象,如匹配的转换指定%dint),成足够尺寸的缓冲器,则创建std::string的缓冲区的内容。


2
很好,我喜欢凯文的答案,尽管他显示了包含和名称空间。只是一个小小的抱怨。:)干得好!
杰森·米克

4
我想说的是,如果您没有C ++ 11支持,这就是要走的路。
Alex

40

如果您安装了Boost(应该这样做):

#include <boost/lexical_cast.hpp>

int num = 4;
std::string str = boost::lexical_cast<std::string>(num);

4
同意加强安装。我认为格式化字符串的频率比通常高。为此,我更喜欢boost :: format例如format(“%02d”,number).str()
Werner Erasmus 2013年

28

使用stringstreams会更容易:

#include <sstream>

int x = 42;          // The integer
string str;          // The string
ostringstream temp;  // 'temp' as in temporary
temp << x;
str = temp.str();    // str is 'temp' as string

或做一个功能:

#include <sstream>

string IntToString(int a)
{
    ostringstream temp;
    temp << a;
    return temp.str();
}

18

我不知道,在纯C ++中。但是对您提到的内容做了一些修改

string s = string(itoa(a));

应该可以,而且很短。


55
itoa()不是标准功能!
漫画家2012年

4
@cartoonist:那是什么?
user541686

20
ANSI-C和C ++中未定义此功能。因此,某些编译器(例如g ++)不支持此功能。
漫画家

17

您可以std::to_string按照Matthieu M.的建议在C ++ 11中使用available :

std::to_string(42);

或者,如果性能是至关重要的(例如,如果你做大量的转换),您可以使用fmt::format_int{} FMT库整数转换std::string

fmt::format_int(42).str();

或C字串:

fmt::format_int f(42);
f.c_str();

后者不做任何动态内存分配,比std::to_stringBoost Karma基准测试快10倍以上。有关更多详细信息,请参见C ++中的快速整数到字符串的转换

请注意,两者都是线程安全的。

不像std::to_stringfmt::format_int不需要C ++ 11,并且可以与任何C ++编译器一起使用。

免责声明:我是{fmt}库的作者。


2
我对声称在保持线程安全(可重入)的同时没有任何动态内存分配的说法感到好奇,所以我阅读了您的代码- c_str()返回指向fmt::FormatInt类内部声明的缓冲区的指针-因此返回的指针在以下位置无效分号-另请参见stackoverflow.com/questions/4214153/lifetime-of-temporaries
Soren

1
是的,行为与std::string::c_str()(因此命名)相同。如果要在完整表达式之外使用它,请构造一个对象,FormatInt f(42);然后可以使用f.c_str()而不会损坏它。
vitaut 2014年

1
当我尝试使用std :: to_string(num)从int转换为string时,我得到了一些奇怪的东西。如果将结果存储在变量中并尝试随着n的增加而像stringNum [1]或stringNum [n]一样访问它,则会出现垃圾。
user8951490

1
这绝对是对这个问题的正确答案:高效且没有状态的标准代码。
xryl669

16

sprintf()非常适合格式转换。然后可以像在1中所做的那样将结果C字符串分配给C ++字符串。


1
嗯是的 但是,在处理C字符串时,我通常依靠snprintf()和友人来解决任何问题。
Throwback1986

1
@MatthieuM。您的评论进一步证明了您不是。如果由于此限制而输出被截断,则返回值是如果有足够的空间将被写入最终字符串的字符数(不包括终止空字节)。因此,size或更大的返回值意味着输出被截断。因此,您可以使用a NULL和0大小来调用它,以获取必要的缓冲区大小。
user1095108 2013年

2
@ user1095108:我认为您是错误的snprintf(请注意SNP前缀)和sprintf(请注意SP前缀)。您将大小传递给前者,注意不要溢出,但是后者不知道缓冲区的大小,因此可能会溢出。
Matthieu M.

1
想法是先调用snprintf变体,然后再调用变sprintf体。由于届时将知道缓冲区的大小,因此调用sprintf变得完全安全。
user1095108 2013年

1
@ user1095108嗯,是的。如果snprintf的第一个缓冲区不足,则返回值会告诉您什么就足够了。我仍将使用snprintf进行第二次调用,因为依靠sprintf和snprintf的实现进行匹配是不必要的危险。
mabraham

11

首先包括:

#include <string>
#include <sstream>

第二种添加方法:

template <typename T>
string NumberToString(T pNumber)
{
 ostringstream oOStrStream;
 oOStrStream << pNumber;
 return oOStrStream.str();
}

使用如下方法:

NumberToString(69);

要么

int x = 69;
string vStr = NumberToString(x) + " Hello word!."

10

使用stringstream进行数字转换很危险!

请参阅http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/,其中告诉您operator<<插入格式化的输出。

根据您当前的语言环境,大于3位的整数可能会转换为4位数字的字符串,并增加一个额外的千位分隔符。

例如,int = 1000可以转换为字符串1.001。这可能会使比较操作根本无法工作。

因此,我强烈建议您使用该std::to_string方式。这更容易,并且可以实现您的期望。

更新(请参阅下面的评论)

C ++ 17提供std::to_chars了一种与语言环境无关的高性能替代方法


2
我同意,如果您需要交换数据,这是一个严重的问题。不幸的是,它也std::to_string使用当前的语言环境(请参阅“注释”部分中的en.cppreference.com/w/cpp/string/basic_string/to_string)。几乎所有标准工具(从stringstream到sprintf,还有其他sscanf)都在使用当前语言环境。直到最近让我难受的时候,我才意识到这一点。当前使用本地生产的东西,不难制造。
Bert Bril

在上面的链接中还声明C ++ 17提供std :: to_chars作为更高性能的独立于语言环境的替代方法。
YesThatIsMyName

不幸的是,在接下来的一年里,我会坚持使用C ++ 11(幸运的是,已经有了很大的改进)。
Bert Bril

1
from_chars和to_chars会很完美,但不幸的是它们没有提供wchar_t变体。
gast128

8

对于C ++ 98,有一些选择:

boost/lexical_cast

Boost不是C ++库的一部分,但是包含许多有用的库扩展。

lexical_cast函数模板提供了支持常见的转换和从时,他们都表示为文本任意类型的方便和一致的形式。
- Boost的文档

#include "boost/lexical_cast.hpp"
#include <string>

int main() {
    int x = 5;
    std::string x_str = boost::lexical_cast<std::string>(x);
    return 0;
}

至于运行时,lexical_cast第一次转换大约要花费80微秒(在我的机器上),然后如果进行冗余处理,则可以大大提高速度。


itoa

此函数未在ANSI-C中定义,也不属于C ++,但某些编译器支持。
- cplusplus.com

这意味着gcc/ g++无法使用编译代码itoa

#include <stdlib.h>

int main() {
    int x = 5;
    char * x_str = new char[2];
    x_str = itoa(x, x_str, 10); // base 10
    return 0;
}

没有要报告的运行时。我没有安装Visual Studio,据报道它可以编译itoa


sprintf

sprintf 是可用于C字符串的C标准库函数,并且是完全有效的替代方法。

如果在printf上使用了format,则使用与要打印的文本组成的字符串组成字符串,但是内容将作为C字符串存储在由str指向的缓冲区中,而不是被打印。
- cplusplus.com

#include <stdio.h>

int main() {
    int x = 5;
    char * x_str = new char[2];
    int chars_written = sprintf(x_str, "%d", x);
    return 0;
}

stdio.h首标可以不是必需的。至于运行时,sprintf第一次转换大约要花费40微秒(在我的机器上),然后如果进行冗余处理,则可以大大提高速度。


stringstream

这是C ++库将整数转换为字符串,反之亦然的主要方法。有类似的姐妹函数可以stringstream进一步限制流的预期用途,例如ostringstream。使用ostringstream专门告诉你的代码的读者,你只打算使用的<<运营商,本质上。将整数转换为字符串时,此功能特别重要。请参阅此问题以进行更详细的讨论。

#include <sstream>
#include <string>

int main() {
    int x = 5;
    std::ostringstream stream;
    stream << x;
    std::string x_str = stream.str();
    return 0;
}

至于运行时,该ostringstream操作大约需要71微秒(在我的机器上),然后如果进行了冗余处理,则此后可以大大提高速度,但不及以前的功能


当然,还有其他选择,您甚至可以将其中一个包装到自己的函数中,但这可以分析一些流行的选择。


感谢您的照顾(C ++ 98用户)
A. B

@AB我无法相信仍然还有C ++ 98用户。
Kotauskas

@VladislavToncharov当您的工作仅是为了支持旧版设备和代码时,您将使用较新的行业标准来处理旧内容。一个夏天前,我正在用Python 2.3编写代码。
约书亚·德特维尔

@JoshuaDetwiler哦,忘记了,对不起。
Kotauskas

4

C ++ 17提供std :: to_chars作为高性能的独立于语言环境的替代方案。


3

添加一些语法糖相当容易,该语法糖可以使用户以类似流的方式实时编写字符串

#include <string>
#include <sstream>

struct strmake {
    std::stringstream s;
    template <typename T> strmake& operator << (const T& x) {
        s << x; return *this;
    }   
    operator std::string() {return s.str();}
};

现在,您可以将所需的任何内容(假设已为其<< (std::ostream& ..)定义了一个运算符)附加strmake()并使用它来代替std::string

例:

#include <iostream>

int main() {
    std::string x =
      strmake() << "Current time is " << 5+5 << ":" << 5*5 << " GST";
    std::cout << x << std::endl;
}

2

已编辑。如果您需要将固定位数的整数快速转换为char * 并用'0'左填充,这是小端架构(所有x86,x86_64等)的示例:

如果要转换两位数的数字:

int32_t s = 0x3030 | (n/10) | (n%10) << 8;

如果要转换三位数的数字:

int32_t s = 0x303030 | (n/100) | (n/10%10) << 8 | (n%10) << 16;

如果要转换四位数的数字:

int64_t s = 0x30303030 | (n/1000) | (n/100%10)<<8 | (n/10%10)<<16 | (n%10)<<24;

依此类推,直到七位数。在这个例子中n是一个给定的整数。转换后,其字符串表示形式可以通过以下方式访问(char*)&s

std::cout << (char*)&s << std::endl;

注意:如果您需要按大端字节顺序使用它,尽管我没有测试过,但这是一个示例:对于三位数,它是int32_t s = 0x00303030 | (n/100)<< 24 | (n/10%10)<<16 | (n%10)<<8;针对四位数(64位拱):int64_t s = 0x0000000030303030 | (n/1000)<<56 | (n/100%10)<<48 | (n/10%10)<<40 | (n%10)<<32;我认为它应该可以工作。


2
字节顺序呢?
shjeff

这不是由于指针别名导致的未定义行为吗?
dgnuff

1
@shjeff感谢您的评论,我在答案中添加了有关字节序的注释。
阿莱克

@dgnuff感谢您指出这一点,尽管我对此没有问题,但您是对的。我略微修改了答案,使其符合严格的别名规则,谢谢。
Alek

1

采用:

#define convertToString(x) #x

int main()
{
    convertToString(42); // Returns const char* equivalent of 42
}

3
尽管有时有用,但仅适用于立即数,不评估变量内容。

对。但绝对是方便的时间
maverick9888

1
仅在编译时使用立即数常量,我认为OP要求使用变量整数进行动态转换
了Ing。GerardoSánchez17年

0

我用:

int myint = 0;
long double myLD = 0.0;

string myint_str = static_cast<ostringstream*>(&(ostringstream() << myint))->str();
string myLD_str = static_cast<ostringstream*>(&(ostringstream() << myLD))->str();

它适用于我的Windows和Linux g ++编译器。


0

这是另一种简单的方法

char str[100];
sprintf(str, "%d", 101);
string s = str;

sprintf 是一种众所周知的将任何数据插入所需格式的字符串中的方法。

您可以将char *数组转换为字符串,如第三行所示。



0

std::to_string()针对数字类型引入的C ++ 11 :

int n = 123; // Input, signed/unsigned short/int/long/long long/float/double
std::string str = std::to_string(n); // Output, std::string

4
嗨!您能否添加一个解释为什么以及如何为问题提供答案?
anothernode

0

采用:

#include<iostream>
#include<string>

std::string intToString(int num);

int main()
{
    int integer = 4782151;

    std::string integerAsStr = intToString(integer);

    std::cout << "integer = " << integer << std::endl;
    std::cout << "integerAsStr = " << integerAsStr << std::endl;

    return 0;
}

std::string intToString(int num)
{
    std::string numAsStr;

    while (num)
    {
        char toInsert = (num % 10) + 48;
        numAsStr.insert(0, 1, toInsert);

        num /= 10;
    }
    return numAsStr;
}

1
对于n≤0完全失败
Toby Speight,

-1
string number_to_string(int x) {

    if (!x)
        return "0";

    string s, s2;
    while(x) {
        s.push_back(x%10 + '0');
        x /= 10;
    }
    reverse(s.begin(), s.end());
    return s;
}

1
感谢您提供此代码段,它可能会提供一些有限的短期帮助。通过说明为什么这是解决问题的好方法,适当的解释将大大提高其长期价值,对于其他类似问题的读者也将更有用。请编辑您的答案以添加一些解释,包括您所做的假设。
Toby Speight

对于n≤0完全失败
Toby Speight,

添加评论,解释您的答案,阅读如何回答
Aksen P


-2
char * bufSecs = new char[32];
char * bufMs = new char[32];
sprintf(bufSecs, "%d", timeStart.elapsed()/1000);
sprintf(bufMs, "%d", timeStart.elapsed()%1000);

12
泄漏记忆,-1从我身边
paulm 2015年

这闻起来像缓冲区溢出。
Kotauskas

-2
namespace std
{
    inline string to_string(int _Val)
    {   // Convert long long to string
        char _Buf[2 * _MAX_INT_DIG];
        snprintf(_Buf, "%d", _Val);
        return (string(_Buf));
    }
}

您现在可以使用to_string(5)


10
虽然此解决方案有效,但我们不建议这样做!以下划线和大写字母开头的名称保留给编译器使用,永远不要使用它们。std也不应该将函数注入名称空间。而且,它似乎不是_MAX_INT_DIG标准宏,因此,如果错误定义了此代码,则该代码很有可能引发未定义的行为。-1
iFreilicht

6
_MAX_INT_DIG是什么,为什么加倍?
保罗

-2

我认为使用stringstream非常简单:

 string toString(int n)
 {
     stringstream ss(n);
     ss << n;
     return ss.str();
 }

 int main()
 {
    int n;
    cin >> n;
    cout << toString(n) << endl;
    return 0;
 }

问题中提到了这一点,但是很慢。
Kotauskas

-3

您使用算法的计数器类型将其转换为字符串。我从Commodore 64电脑的编程中获得了这项技术。这对游戏编程也很有好处。

  • 您取整数并取以10的幂进行加权的每个数字,因此假设整数为950。

    • 如果整数等于或大于100,000,则减去100,000,并在[[000000]]处增加字符串中的计数器;
      继续这样做,直到100,000个位置没有更多的数字为止。降低十的幂。

    • 如果整数等于或大于10,000,则减去10,000,并在[“ 000000”] + 1位置的字符串中增加计数器;
      继续这样做,直到没有更多的数字10,000。

  • 掉十的力量

  • 重复图案

我知道950太小,无法用作示例,但我希望您能理解。


描述算法而不是在代码中显示示例不是很有帮助。
cdeerinck
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.