ChatGPT解决这个技术问题 Extra ChatGPT

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

在 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();
我认为您提供的两种方法都是很好的解决方案。这取决于您需要执行此操作的上下文。如果您已经在使用流,例如读取或写入文件,那么您的第二种方法是最好的。如果您需要将 int 作为字符串传递给函数参数,那么 itoa 可能是一种简单的方法。但大多数时候,在处理文件时会发生 int 到 string 的转换,因此流是合适的。
选项 1 对您有什么帮助?我的理解是 itoa() 采用三个参数。
itoa 将比等效的流更快。还有一些方法可以通过 itoa 方法重新使用字符串缓冲区(如果您经常生成字符串,则避免堆分配。例如,对于一些快速更新的数字输出)。或者,您可以生成自定义流缓冲区以减少一些分配开销等。首先构建流也不是低成本的冒险。
@Pete:一旦你开始担心哪个更快,你会想看看 stackoverflow.com/questions/4351371/…
请注意, itoa() 不是标准的一部分,因此使用它会使您的代码不可移植,因为并非所有编译器都支持它。对于 Linux,除非您使用不支持此功能的 GCC 以外的其他东西,否则您肯定会出局。如果您有 C++0x,请遵循@Matthieu 在他的回答中提出的建议。如果不是这种情况,请使用 stringstream,因为它是一个得到很好支持的功能,并且您的代码应该与那里的每个 C++ 编译器兼容。作为替代方案,您始终可以使用 sprintf()。

t
the_storyteller

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.5 in n3242


to_string 不是 std 修复的成员:stackoverflow.com/questions/12975341/…
或者根据您的编译器,只需设置正确的语言标准:g++ -std=c++11 someFile.cc
@史蒂夫:应该是。在我所知道的每个编译器中,它都是 std 的成员,除了一个。
@Matthiew M。我正在使用您建议的相同内容,但出现此错误:Error : No instance of overloaded function "std::to_string" matches the argument list 我正在使用 VS2010 c++
@Flying:在VS2010下,您必须将转换整数显式转换为以下类型之一 [_Longlong, _ULonglong, long double];即:string s = to_string((_ULonglong)i);
D
DevSolar

C++20 更新: std::format 现在是惯用的方式。

C++17 更新:

几年后与@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++ 98)答案:

由于“将 ... 转换为字符串”是一个反复出现的问题,因此我总是在 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++11std::to_string),并且不需要任何第三方包含(如果你不能使用Boostlexical_cast<>);不过,这两种其他解决方案都有更好的性能。


我对 dynamic_cast 不是很熟悉,但我正在使用 clang 进行编译,所以它会抱怨它。如果我只是省略 dynamic_cast 那么它编译得很好;在这种情况下,dynamic_cast 的用途是什么?我们已经创建了一个 ostringstream,那么为什么要转换它呢?
@Mathew:我的答案中的链接导致对构造的每个部分进行详细描述。当我们创建一个 ostringstream 时,我们在其上调用了 operator<<(),它返回 ostream &——没有定义 .str()。我真的很想知道在没有演员阵容的情况下 clang 将如何使这项工作(或者为什么它会产生错误)。这个结构在很多地方都发布过,而且我已经在许多不同的编译器上使用它十多年了,包括 MSVC、GCC 和 XLC,所以我很惊讶 clang 对它犹豫不决。
只是出于好奇而参加聚会,并投了反对票。原因:对一个不优雅且可能很慢的解决方案投了太多票。 1.宏用法。我不会系统地对任何宏皱眉,但是这个宏太短了,最终客户总是害怕重复论证,除了害怕不受保护的多行宏。 (不受 do{}while(0) 保护) 2. dynamic_cast。似乎您只需要一个 static_cast ,除非您想断言该库确实如您所愿实现。在这种情况下,您应该改用 boost::polymorphic_downcast。
@v.oddou:当然,你可以自由批评。但是 1. 是无效的——宏是单个语句,do { } while( 0 ) 不会添加任何内容。有了 2. 和 3. 你可能明白了——这可以通过静态转换来完成,也许你们中的一个模板向导可以提出一个“更好”的界面。但正如我所说,这绝不是我自己的发明。环顾四周,这个宏(宏!)是相当普遍的。这就是 POLA 本身的一个例子。我可能会玩弄它以使其更加“流线型”。
@v.oddou:看看我在 C++17 带给我们的东西中发现了什么。 :-) 我希望你喜欢更新后的答案。
J
Jerry Coffin

当前的 C++

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

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

标准将这些定义为等效于使用 sprintf 进行转换(使用与提供的对象类型匹配的转换说明符,例如 %d 用于 int)到足够大小的缓冲区,然后创建一个 { 4} 该缓冲区的内容。

旧 C++

对于较旧的(C++11 之前的)编译器,可能最常见的简单方法基本上是将您的第二选择包装到通常名为 lexical_cast 的模板中,例如 Boost 中的那个,因此您的代码如下所示:

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

其中一个优点是它也支持其他类型的转换(例如,在相反的方向上也同样有效)。

另请注意,尽管 Boost lexical_cast 开始时只是写入 stringstream,然后从流中提取回来,但它现在有一些添加。首先,添加了许多类型的特化,因此对于许多常见类型,它比使用 stringstream 快得多。其次,它现在检查结果,因此(例如)如果您从字符串转换为 int,如果字符串包含无法转换为 int 的内容(例如,{ 6} 会成功,但 123abc 会抛出)。


很好,我更喜欢 Kevin 的回答,尽管他展示了包含和命名空间。只是一个小小的抱怨。 :) 干得好,不过!
如果您没有 C++11 支持,我会说这是要走的路。
P
Peter Mortensen

我通常使用以下方法:

#include <sstream>

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

详见here


@lifebalance:我从未见过这种行为。
@lifebalance:您不需要 clear() 新创建的 ostringstream 对象。 clear() 重置错误/eof 标志,并且尚未生成任何错误/eof 条件。
@Rasoul NumberToString(23213.123) 产生 23213.1std::to_string(23213.123) 产生 23213.123000 那里发生了什么?
@KillzoneKid 这是因为 std' ostream 是有状态的(这意味着保留任何先前的状态更改,例如十进制数字的数量),而此方法以默认状态开始。
使用 .flags(...) 阅读 &清除格式标志,.str("") 清除现有字符串。
v
vitaut

您可以将 C++11 中的 std::to_string 用作 suggested by Matthieu M.

std::to_string(42);

或者,如果性能至关重要(例如,如果您进行大量转换),您可以使用 {fmt} 库中的 fmt::format_int 将整数转换为 std::string

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

或 C 字符串:

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

后者不进行任何动态内存分配,并且在 Boost Karma 基准测试中比 std::to_string 的 libstdc++ 实现快 70% 以上。有关详细信息,请参阅 Converting a hundred million integers to strings per second

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


我很好奇在保持线程安全(可重入)的同时没有任何动态内存分配的说法,所以我读了你的代码——c_str() 返回一个指向在 fmt::FormatInt 类中声明的缓冲区的指针——所以返回的指针在分号处无效 -- 另请参阅 stackoverflow.com/questions/4214153/lifetime-of-temporaries
是的,与 std::string::c_str() 的行为相同(因此命名)。如果你想在完整的表达式之外使用它构造一个对象 FormatInt f(42); 那么你可以使用 f.c_str() 而没有它被破坏的危险。
当我尝试使用 std::to_string(num) 从 int 转换为 string 时,我得到了一些奇怪的东西。如果我将结果存储在一个变量中并尝试在 n 增加时像 stringNum[1] 或 stringNum[n] 一样访问它,我会得到垃圾。
这绝对是这个问题的正确答案:高效且标准的无状态代码。
K
Kevin

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

#include <boost/lexical_cast.hpp>

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

同意boost安装。我认为通常会格式化字符串。为此,我更喜欢 boost::format 例如 format("%02d", number ).str()
P
Peter Mortensen

使用字符串流会更容易:

#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();
}

u
user541686

不是我所知道的,在纯 C++ 中。但是对你提到的内容稍作修改

string s = string(itoa(a));

应该可以工作,而且很短。


itoa() 不是标准函数!
@cartoonist:那是什么?
此函数未在 ANSI-C 和 C++ 中定义。因此某些编译器(例如 g++)不支持它。
cplusplus.com/reference/cstdlib/itoa:“可移植性此函数未在 ANSI-C 中定义,也不是 C++ 的一部分,但某些编译器支持。” gcc.godbolt.org/z/MaEEf4evW
b
bluish

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


呵呵,是的。但是,在处理 C 字符串时,我通常依靠 snprintf() 和朋友来处理任何重要的事情。
@MatthieuM。您的评论进一步证明,您不是。如果输出由于此限制而被截断,则返回值是字符数(不包括终止的空字节),如果有足够的可用空间,这些字符将被写入最终字符串。因此,大小或更大的返回值意味着输出被截断。因此,您使用 NULL 和零大小调用它以获得必要的缓冲区大小。
@user1095108:我认为您弄错了 snprintf(注意 SNP 前缀)和 sprintf(注意 SP 前缀)。您将大小传递给前者,它注意不要溢出,但是后者不知道缓冲区的大小,因此可能会溢出。
我们的想法是先调用 snprintf 变体,然后再调用 sprintf 变体。由于此时缓冲区大小已知,调用 sprintf 变得完全安全。
@user1095108 啊,是的。如果 snprintf 的第一个缓冲区不足,则返回值会告诉您什么是足够的。我仍然会在第二次调用中使用 snprintf,因为依赖 sprintf 和 snprintf 的实现来匹配是不必要的危险。
q
quamrana

首先包括:

#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!."

Y
YesThatIsMyName

使用 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 作为更高性能的独立于语言环境的替代方案


如果您需要交换数据,我同意这是一个严重的问题。不幸的是,std::to_string 也使用当前语言环境(请参阅 en.cppreference.com/w/cpp/string/basic_string/to_string 的“注释”部分)。几乎所有标准工具(从 stringstreams 到 sprintf,还有 sscanf 等)都使用当前语言环境。我直到最近才意识到这一点,当时它给我带来了沉重的打击。目前用的是国产的,不难做。
在上面的链接中,还声明 C++17 提供 std::to_chars 作为更高性能的独立于语言环境的替代方案。
不幸的是,我在接下来的一年里坚持使用 C++11(幸运的是,已经有了很大的改进)。
from_chars 和 to_chars 将是完美的,但不幸的是它们没有提供 wchar_t 变体。
W
Waqar

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


对于性能密集型应用程序,您需要这个而不是 stringstream 路由。
M
Manish Kumawat

在 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;
}

A
Alek

已编辑。如果您需要将具有固定位数的整数快速转换为 char* 左填充 '0',这是 little-endian 体系结构(所有 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;我认为它应该工作。


字节顺序呢?
@shjeff 感谢您的评论,我在答案中添加了关于字节序的注释。
@dgnuff 感谢您指出这一点,尽管我对此没有任何问题,但您是对的。我稍微修改了答案,使其符合严格的别名规则,谢谢。
A
AndreyS Scherbakov

添加一些语法糖是相当容易的,它允许人们以类似流的方式即时组合字符串

#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;
}

i
isanae

利用:

#define convertToString(x) #x

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

仅适用于文字数字,不评估可变内容,尽管有时很有用。
正确的。但绝对方便的时候
仅在编译时使用文字常量数字,我认为 OP 要求使用可变整数进行动态转换
P
Peter Mortensen

我用:

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++ 编译器。


P
Peter Mortensen

这是另一种简单的方法

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

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

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


T
Tur1ng

如果您使用 MFC,则可以使用 CString

int a = 10;
CString strA;
strA.Format("%d", a);

您应该注意,这是一个仅限 Microsoft 的扩展:msdn.microsoft.com/en-us/library/ms174288.aspx
我喜欢 CString::Format() 的想法。不幸的是,它只有非便携式 MS。
我已经更新了我的答案,以包含来自您的评论@JonnyJD 的信息,因为 5 年后我一直对此投反对票。
K
Kotauskas

C++11 为数字类型引入了 std::to_string()

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

你好!您能否解释一下为什么以及如何提供问题的答案?
P
Peter Mortensen
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;
}

感谢您提供此代码片段,它可能会提供一些有限的短期帮助。通过说明为什么这是一个很好的问题解决方案,正确解释would greatly improve它的长期价值,并使其对有其他类似问题的未来读者更有用。请edit您的回答以添加一些解释,包括您所做的假设。
n≤0 完全失败
添加评论,解释您的答案,阅读how to answer
P
Peter Mortensen

这对我有用 -

我的代码:

#include <iostream>
using namespace std;

int main()
{
    int n = 32;
    string s = to_string(n);
    cout << "string: " + s  << endl;
    return 0;
}

主要使用什么? stringstream
@PeterMortensen 仔细看,它是 std::to_string()
我有 using namespace std; :)
A
Archie

int i = 255; std::string s = std::to_string(i);

在 c++ 中,to_string() 将通过将值表示为字符序列来创建整数值的字符串对象。


虽然此代码可能会解决 OP 的问题,但最好包括说明您的代码如何解决 OP 的问题。通过这种方式,未来的访问者可以从您的帖子中学习,并将其应用到他们自己的代码中。 SO 不是编码服务,而是知识资源。此外,高质量、完整的答案更有可能得到支持。这些功能,以及所有帖子都是独立的要求,是 SO 作为一个平台的一些优势,使其与论坛区分开来。您可以编辑以添加其他信息和/或使用源文档补充您的解释。
P
PYK

使用普通的标准 stdio 标头,您可以将 sprintf 上的整数转换为缓冲区,如下所示:

#include <stdio.h>
int main()
  {
  int x=23;
  char y[2]; //the output buffer
  sprintf(y,"%d",x);
  printf("%s",y)
  }

请记住根据您的需要照顾您的缓冲区大小[字符串输出大小]


虽然我喜欢您的回答,但这是不正确的:您忘记了标记转换字符串结尾的空字符(即,在这种情况下,输出字符串的大小必须至少为 3)。请参阅gnu.org/software/libc/manual/html_node/…
T
Tayyab Mazhar

利用:

#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;
    bool isNegative = num < 0;
    if(isNegative) num*=-1;

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

       num /= 10;
    }while (num);
  
    return isNegative? numAsStr.insert(0, 1, '-') : numAsStr;
}

n≤0 完全失败
P
Peter Mortensen
char * bufSecs = new char[32];
char * bufMs = new char[32];
sprintf(bufSecs, "%d", timeStart.elapsed()/1000);
sprintf(bufMs, "%d", timeStart.elapsed()%1000);

泄漏内存,-1 从我这里
这闻起来像缓冲区溢出。
P
Peter Mortensen
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)


虽然此解决方案有效,但非常不鼓励!以下划线和大写字母开头的名称是为编译器保留的,你永远不应该使用它们。将函数注入 std 命名空间也不是您应该做的事情。此外,_MAX_INT_DIG 似乎不是标准宏,因此如果定义错误,此代码很有可能引发未定义的行为。 -1
什么是 _MAX_INT_DIG,为什么会翻倍?
P
Peter Mortensen

您使用计数器类型的算法来转换为字符串。我从对 Commodore 64 计算机编程中获得了这项技术。它也适用于游戏编程。

您取整数并取以 10 的幂加权的每个数字。因此假设整数为 950。如果整数等于或大于 100,000,则减去 100,000 并在 ["000000"]; 处增加字符串中的计数器;继续这样做,直到位置 100,000 中没有更多数字为止。再降一个十的幂。如果整数等于或大于 10,000,则减去 10,000 并增加字符串中 ["000000"] + 1 位置处的计数器;继续这样做,直到位置 10,000 没有更多数字为止。

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

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

放下另一个十的幂

重复模式

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


描述算法不是很有帮助,而不是在代码中显示示例。
P
Peter Mortensen

我认为使用 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;
 }

问题中提到了这一点,不幸的是速度很慢。