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

Nem*_*emo 1488 c++ string int type-conversion

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

(1)

int a = 10;
char *intStr = itoa(a);
string str = string(intStr);
Run Code Online (Sandbox Code Playgroud)

(2)

int a = 10;
stringstream ss;
ss << a;
string str = ss.str();
Run Code Online (Sandbox Code Playgroud)

Mat*_* M. 1975

C++ 11引入std::stoi(以及每种数字类型的变体)和std::to_stringC的对应部分atoi,itoa但以术语表示std::string.

#include <string> 

std::string s = std::to_string(42);
Run Code Online (Sandbox Code Playgroud)

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

auto s = std::to_string(42);
Run Code Online (Sandbox Code Playgroud)

注:参见[string.conversions] (21.5n3242)

  • `to_string`不是`std`修复的成员:http://stackoverflow.com/questions/12975341/to-string-is-not-a-member-of-std-says-so-g (192认同)
  • 或者根据您的编译器,只需设置正确的语言标准:`g ++ -std = c ++ 11 someFile.cc` (33认同)
  • @Flying:在VS2010下你必须显式地将转换整数转换为以下类型之一[_Longlong,_ULonglong,long double]; 即:`string s = to_string((_ ULonglong)i);` (18认同)
  • @Steve:它应该是.它是我所知道的每个编译器中`std`的成员,除了一个. (12认同)
  • @Matthiew M.我使用你建议的相同但我得到这个错误:`错误:没有重载函数的实例"std :: to_string"匹配参数列表`我正在使用VS2010 c ++ (5认同)
  • @uoɥʇʎPʎzɐɹC:我鼓励您更仔细地查看代码示例.`42`(一个文字)正被转换为`s`(一个`std :: string`). (3认同)
  • 注意:它在 NDK 中不起作用。to_string 未在 NDK 中实现。 (2认同)
  • @GabrielStaples:意见问题。当谈到变量时,我自己属于 AAA(几乎总是自动)阵营,尽管为了清楚起见,我确实使用了“装饰”(const、&amp;、*)。不过,我系统地详细阐述了函数签名,因此类型永远不会遥远。我已经习惯了使用 Rust,它的类型推断更好,因此类型注释更少,而且对我来说感觉很自然。 (2认同)

Dev*_*lar 179

几年后,与@ 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();
}
Run Code Online (Sandbox Code Playgroud)

用法:

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 ) );
Run Code Online (Sandbox Code Playgroud)

原始答案:

由于"将...转换为字符串"是一个反复出现的问题,我总是在我的C++源代码的中心标题中定义SSTR()宏:

#include <sstream>

#define SSTR( x ) static_cast< std::ostringstream & >( \
        ( std::ostringstream() << std::dec << x ) ).str()
Run Code Online (Sandbox Code Playgroud)

用法很简单:

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 ) );
Run Code Online (Sandbox Code Playgroud)

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

  • 刚刚来到派对的好奇心,并且投了赞成票.理由:对于一个不优雅且可能很慢的解决方案投票太多.宏观用法 我并没有系统地对任何宏观都不屑一顾,但是这个宏太短了,终端客户总是害怕重复这个论点,除了对未受保护的多线宏的恐惧之外.(不受do {}和(0)保护)2.dynamic_cast.看来你在这里只需要一个static_cast,除非你想断言你的库确实是按照你的希望实现的.在这种情况下,你应该使用boost :: polymorphic_downcast. (5认同)
  • 我对`dynamic_cast`不是很熟悉,但我正在使用clang进行编译,所以它抱怨它.如果我只省略`dynamic_cast`那么它编译得很好; 在这种情况下,`dynamic_cast`的目的是什么?我们已经在创建一个`ostringstream`了,为什么要施展呢? (2认同)
  • @Mathew:我的答案中的链接导致对构造的每个部分的详细描述.虽然我们*创建了一个`ostringstream`,但我们在其上调用了`operator <<()`,它返回`ostream&` - 未定义`.str()`.我真的很想知道clang如何在没有演员的情况下完成这项工作(或者为什么它会产生错误).这个结构发表在很多地方,我已经在许多不同的编译器上使用了十多年,包括MSVC,GCC和XLC,所以我很惊讶它的铿锵声. (2认同)
  • @ v.oddou:当然,你可以自由批评.但是1.无效 - 宏是单个语句,`do {} while(0)`不会添加任何内容.使用2.和3.你可能有一点 - 这可以通过静态强制转换完成,也许你们中的一个模板向导可以提出一个"更好"的界面.但正如我所说,这绝不是我自己的发明.环顾四周,这个宏(宏!)非常普遍.这是POLA本身的一个案例.我可能会用这个玩具来使它更"流线型". (2认同)

Ras*_*oul 104

我通常使用以下方法:

#include <sstream>

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

这里详细描述.

  • @lifebalance:我从未见过这样的行为. (14认同)
  • @lifebalance:你不需要`clear()`一个新创建的`ostringstream`对象.`clear()`重置error/eof标志,并且还没有生成任何错误/ eof条件. (14认同)
  • 在使用`ss`之前,你需要`ss.clear()`它。如果没有这个初始化,我已经看到了意想不到的结果。 (2认同)
  • @Rasoul`NumberToString(23213.123)`产生`23213.1`而`std :: to_string(23213.123)`产生`23213.123000`那里会发生什么? (2认同)

Jer*_*fin 85

可能最常见的简单方法基本上将您的第二个选择包装到名为的模板中lexical_cast,例如Boost中的模板,因此您的代码如下所示:

int a = 10;
string s = lexical_cast<string>(a);
Run Code Online (Sandbox Code Playgroud)

这样做的一个好处是它也支持其他演员表(例如,在相反的方向上工作也一样).

另请注意,虽然Boost lexical_cast最初只是写入字符串流,然后从流中提取出来,但它现在有一些补充.首先,添加了很多类型的特化,因此对于许多常见类型,它比使用字符串流要快得多.其次,它现在检查结果,所以(例如)如果从字符串转换为a int,如果字符串包含无法转换为a的内容int(例如,1234会成功,但123abc会抛出),它可以抛出异常.

从C++ 11开始,有一个std::to_string函数为整数类型重载,所以你可以使用如下代码:

int a = 20;
std::string s = to_string(a);
Run Code Online (Sandbox Code Playgroud)

标准将这些定义为等同于使用sprintf(使用与提供的对象类型匹配的转换说明符,例如%dfor int)进行转换,将其转换为足够大小的缓冲区,然后创建std::string该缓冲区的内容.

  • 如果你没有C++ 11的支持,我会说这是要走的路. (4认同)
  • 很好,我更喜欢凯文的回答,不过他展示了包含和命名空间.只是一个小小的抱怨.:)虽然干得好! (2认同)

小智 41

如果你安装了Boost(你应该):

#include <boost/lexical_cast.hpp>

int num = 4;
std::string str = boost::lexical_cast<std::string>(num);
Run Code Online (Sandbox Code Playgroud)

  • 同意加速安装.我认为通常会有人格式化字符串.为此,我更喜欢boost :: format,例如format("%02d",number).str() (4认同)

小智 27

使用stringstream会不会更容易?

#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
Run Code Online (Sandbox Code Playgroud)

或者做一个功能:

#include <sstream>

string IntToString(int a)
{
    ostringstream temp;
    temp << a;
    return temp.str();
}
Run Code Online (Sandbox Code Playgroud)


Meh*_*dad 19

在纯C++中,我不知道.但对你提到的内容进行一点修改

string s = string(itoa(a));
Run Code Online (Sandbox Code Playgroud)

应该工作,而且很短.

  • `itoa()`不是标准函数! (53认同)
  • ANSI-C和C++中未定义此函数.所以g ++等编译器不支持它. (18认同)
  • @cartoonist:那是什么? (4认同)

Thr*_*986 16

sprintf()非常适合格式转换.然后,您可以像在1中一样将结果C字符串分配给C++字符串.

  • 呵呵,是的。然而,在处理 C 字符串时,我通常依赖 snprintf() 和朋友来处理任何重要的事情。 (2认同)
  • @ user1095108:我认为你错了`snprintf`(注意**SNP**前缀)和`sprintf`(注意**SP**前缀).您将大小传递给前者,并且注意不要溢出,但后者不知道缓冲区的大小,因此可能溢出. (2认同)

vit*_*aut 16

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

std::to_string(42);
Run Code Online (Sandbox Code Playgroud)

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

fmt::format_int(42).str();
Run Code Online (Sandbox Code Playgroud)

或C字符串:

fmt::format_int f(42);
f.c_str();
Run Code Online (Sandbox Code Playgroud)

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

不同std::to_string,fmt::format_int不需要C++ 11并且可以与任何C++编译器一起使用.

免责声明:我是C++格式库的作者.

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

Jan*_*tke 12

C++ 随着时间的推移而不断发展,并将 an 转换int为字符串的方法也随之发展。\n我将在此答案中提供摘要。\n请注意,某些方法不会std::string直接为您提供char*. 您可以轻松地转换char*为前者,并且在某些情况下避免std::string.

\n

比较

\n

下表按最新到最新的顺序比较了所有选项(仅 C++ 标准选项,无第三方库)。

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n
方法结果优点缺点
std::格式
std::string\xe2\x9c\x94\xef\xb8\x8f 通用方法(对于可格式化类型)
\xe2\x9c\x94\xef\xb8\x8f 支持通用基数,并且语言环境
\xe2\x9d\x8c 编译速度慢
\xe2\x9d \x8c 慢速(转发到std::vformat
std::to_chars
写给
char[]
\xe2\x9c\x94\xef\xb8\x8f 快速且零开销(无动态分配)
\xe2\x9c\x94\xef\xb8\x8f 支持任何基数作为运行时参数
\xe2\x9d\x8c 仅适用于基本类型
\xe2\x9d\x8c 接口不符合人体工程学
std::to_string
std::string\xe2\x9c\x94\xef\xb8\x8f 简洁且不言自明
\xe2\x9c\x94\xef\xb8\x8f 零开销(如果需要)std::string\
xe2\x9d\x8c 仅适用于基本类型
\xe2 \x9d\x8c 仅以 10 为基数
std::ostringstream
std::string\xe2\x9c\x94\xef\xb8\x8f 通用方法(对于带有<<运算符的类型)
\xe2\x9c\x94\xef\xb8\x8f 考虑语言环境(例如可以更改基数)
\xe2\x9d\x8c 慢,高流的开销
std::sprintf
写给
char[]
\xe2\x9c\x94\xef\xb8\x8f 最小汇编输出
\xe2\x9c\x94\xef\xb8\x8f 支持某些基数
\xe2\x9c\x94\xef\xb8\x8f 与 C 兼容,与所有其他方法不同
\xe2\x9d\x8c 仅适用于基本类型
\xe2\x9d\x8c 接口不符合人体工程学
\xe2\x9d\x8c 无类型安全
\n

推荐做法

\n

std::to_string如果您只需将 an 转换int为十进制字符串,请使用。它简单、优雅、正确。

\n

如果您无法使用std::to_string,请根据您需要的功能选择其他选项。更喜欢更现代的解决方案(例如 )std::to_chars而不是较旧的解决方案(例如std::sprintf.

\n

例子

\n
std::format
\n
std::string d = std::format("{}", 100);   // d = "100"\nstd::string h = std::format("{:#x}", 15); // h = "0xf"\n
Run Code Online (Sandbox Code Playgroud)\n
std::to_chars
\n
std::array<char, 5> a;\nauto [ptr, ec] = std::to_chars(a.data(), a.data() + a.size(), 1234);\n// a = {\'1\', \'2\', \'3\', \'4\', indeterminate} (no null terminator!)\n// ptr points to 4, and ec == std::errc{}\n// notice that there is no null terminator\nstd::string_view view(a.data(), ptr); // string_view doesn\'t require null terminators\nstd::string s(a.data(), ptr); // wrapping in a std:string kinda defeats the point\n
Run Code Online (Sandbox Code Playgroud)\n
std::to_string
\n
std::string d = std::to_string(100); // d = "100"\n
Run Code Online (Sandbox Code Playgroud)\n
std::ostringstream
\n
std::string d = (std::ostringstream() << 100).str();            // d = "100"\nstd::string h = (std::ostringstream() << std::hex << 15).str(); // h = "0xf"\n
Run Code Online (Sandbox Code Playgroud)\n

注意:这些单行代码依赖于LWG 1203 (C++20),但最近的编译器也允许在 C++11 模式下使用它。更新您的编译器,或者创建一个单独的std::ostringstream stream变量(如果它不起作用)。

\n
sprintf/snprintf
\n
char a[20];\nsprintf(a, "%d", 15);                // a = {\'1\', \'5\', \'\\0\', ?, ?, ?, ...}\nsnprintf(a, sizeof(a), "%#x", 15);   // a = {\'0\', \'x\', \'f\', \'\\0\', ?, ?, ...}\nstd::string s = a;\n
Run Code Online (Sandbox Code Playgroud)\n


小智 11

首先包括:

#include <string>
#include <sstream>
Run Code Online (Sandbox Code Playgroud)

第二个添加方法:

template <typename T>
string NumberToString(T pNumber)
{
 ostringstream oOStrStream;
 oOStrStream << pNumber;
 return oOStrStream.str();
}
Run Code Online (Sandbox Code Playgroud)

使用这样的方法:

NumberToString(69);
Run Code Online (Sandbox Code Playgroud)

要么

int x = 69;
string vStr = NumberToString(x) + " Hello word!."
Run Code Online (Sandbox Code Playgroud)


小智 10

在C++11中,我们可以使用“to_string()”函数将int转换为字符串:

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int x = 1612;
    string s = to_string(x);
    cout << s<< endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Yes*_*ame 9

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

请参阅http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/,其中说明operator<<插入格式化输出.

根据您当前的区域设置,大于3位的整数,可以转换为4位数的字符串,添加额外的千位分隔符.

例如,int = 1000可以转换为字符串1.001.这可能使比较操作根本不起作用.

所以我强烈建议使用这种std::to_string方式.它更容易,做你期望的.

  • 我同意如果您需要交换数据,这是一个严重的问题.不幸的是,`std :: to_string`也使用当前的语言环境(参见http://en.cppreference.com/w/cpp/string/basic_string/to_string,'Notes'部分).几乎所有标准工具(从stringstreams到`sprintf`,还有`sscanf`等)都使用当前的语言环境.直到最近,我还没有意识到这一点.目前使用自家种植的东西,不难做出. (2认同)

Jos*_*ler 7

对于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;
}
Run Code Online (Sandbox Code Playgroud)

至于运行时,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;
}
Run Code Online (Sandbox Code Playgroud)

没有运行时报告.我没有安装Visual Studio,据说可以编译itoa.


sprintf

sprintf 是一个C标准库函数,适用于C字符串,是一个完全有效的选择.

如果在printf上使用了格式,则使用与打印时相同的文本组成一个字符串,但不是打印,而是将内容作为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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

至于运行时,ostringstream操作大约需要71微秒(在我的机器上),然后如果冗余完成则会大大加快,但不会像以前的功能那样多.


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


小智 7

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


Ale*_*lek 6

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

如果您要转换两位数:

int32_t s = 0x3030 | (n/10) | (n%10) << 8;
Run Code Online (Sandbox Code Playgroud)

如果您要转换三位数:

int32_t s = 0x303030 | (n/100) | (n/10%10) << 8 | (n%10) << 16;
Run Code Online (Sandbox Code Playgroud)

如果您要转换四位数:

int64_t s = 0x30303030 | (n/1000) | (n/100%10)<<8 | (n/10%10)<<16 | (n%10)<<24;
Run Code Online (Sandbox Code Playgroud)

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

std::cout << (char*)&s << std::endl;
Run Code Online (Sandbox Code Playgroud)

注意:如果您需要大端字节顺序,虽然我没有测试它,但这里有一个示例:对于三位数,它适用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;我认为它应该可以工作。


归档时间:

查看次数:

2727891 次

最近记录:

5 年,11 月 前