如何在c++中解析字符串为int ?

c++用什么方法把字符串(char *)解析成int?健壮和清晰的错误处理是一个加分项(而不是返回0)。

248360 次浏览

传统的C方式仍然有效。我推荐散步或散步。在返回状态和'endPtr'之间,您可以给出良好的诊断输出。它还可以很好地处理多个碱基。

你可以使用stringstream的

int str2int (const string &str) {
stringstream ss(str);
int num;
ss >> num;
return num;
}
你可以使用提高的lexical_cast,在更通用的接口中使用包装这lexical_cast<Target>(Source)在失败时抛出bad_lexical_cast

这是比atoi()更安全的C方式

const char* str = "123";
int i;


if(sscanf(str, "%d", &i)  == EOF )
{
/* error */
}

c++的标准库stringstream:(感谢CMS)

int str2int (const string &str) {
stringstream ss(str);
int num;
if((ss >> num).fail())
{
//ERROR
}
return num;
}

使用提高库:(感谢jk)

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


try
{
std::string str = "123";
int number = boost::lexical_cast< int >( str );
}
catch( const boost::bad_lexical_cast & )
{
// Error
}

编辑:修正了stringstream版本,以便它处理错误。(感谢CMS和jk对原文的评论)

你可以使用c++标准库中的a stringstream:

stringstream ss(str);
int x;
ss >> x;


if(ss) { // <-- error handling
// use x
} else {
// not a number
}

流状态将被设置为失败 当遇到非数字时 正在读取一个整数

有关c++中错误处理和流的陷阱,请参阅流陷阱

c++ String工具库(StrTk)有以下解决方案:

static const std::size_t digit_table_symbol_count = 256;
static const unsigned char digit_table[digit_table_symbol_count] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF - 0x07
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x08 - 0x0F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10 - 0x17
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x18 - 0x1F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20 - 0x27
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x28 - 0x2F
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x38 - 0x3F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40 - 0x47
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x48 - 0x4F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x50 - 0x57
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x58 - 0x5F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x60 - 0x67
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x68 - 0x6F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x70 - 0x77
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x78 - 0x7F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x80 - 0x87
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x88 - 0x8F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x90 - 0x97
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x98 - 0x9F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA0 - 0xA7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA8 - 0xAF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB0 - 0xB7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB8 - 0xBF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC0 - 0xC7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC8 - 0xCF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD0 - 0xD7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD8 - 0xDF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0 - 0xE7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE8 - 0xEF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xF0 - 0xF7
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF  // 0xF8 - 0xFF
};


template<typename InputIterator, typename T>
inline bool string_to_signed_type_converter_impl_itr(InputIterator begin, InputIterator end, T& v)
{
if (0 == std::distance(begin,end))
return false;
v = 0;
InputIterator it = begin;
bool negative = false;
if ('+' == *it)
++it;
else if ('-' == *it)
{
++it;
negative = true;
}
if (end == it)
return false;
while(end != it)
{
const T digit = static_cast<T>(digit_table[static_cast<unsigned int>(*it++)]);
if (0xFF == digit)
return false;
v = (10 * v) + digit;
}
if (negative)
v *= -1;
return true;
}

InputIterator可以是unsigned char*、char*或std::string迭代器,T应该是signed int,例如signed int、int或long

我认为这三个环节可以概括:

  • http://tinodidriksen.com/2010/02/07/cpp-convert-int-to-string-speed/ < a href = " http://tinodidriksen.com/2010/02/07/cpp-convert-int-to-string-speed/ " > < / >
  • <强> < a href = " http://tinodidriksen.com/2010/02/16/cpp-convert-string-to-int-speed/ " > http://tinodidriksen.com/2010/02/16/cpp-convert-string-to-int-speed/ < / > < / >强
  • <强> < a href = " http://www.fastformat.org/performance.html " > http://www.fastformat.org/performance.html < / > < / >强

Stringstream和lexical_cast解决方案与lexical cast使用Stringstream大致相同。

一些词法强制转换的特殊化使用不同的方法,详细信息请参见http://www.boost.org/doc/libs/release/boost/lexical_cast.hpp < a href = " http://www.boost.org/doc/libs/release/boost/lexical_cast.hpp " > < / >。整数和浮点数现在专门用于整型到字符串的转换。

可以根据自己的需要专门化lexical_cast,并使其快速运行。这将是让各方满意的最终解决方案,干净而简单。

前面提到的文章展示了转换整数<->字符串的不同方法之间的比较。以下方法是有意义的:旧c-way,精神。Karma, fastformat,简单的循环。

Lexical_cast在某些情况下是可以的,例如int到字符串的转换。

使用词法强制转换将字符串转换为int不是一个好主意,因为它比atoi慢10-40倍,这取决于所使用的平台/编译器。

karma似乎是将整数转换为字符串的最快的库。

ex.: generate(ptr_char, int_, integer_number);

上面文章中提到的基本简单循环是将字符串转换为int的最快方法,显然不是最安全的方法,strtol()似乎是更安全的解决方案

int naive_char_2_int(const char *p) {
int x = 0;
bool neg = false;
if (*p == '-') {
neg = true;
++p;
}
while (*p >= '0' && *p <= '9') {
x = (x*10) + (*p - '0');
++p;
}
if (neg) {
x = -x;
}
return x;
}

不要做什么

这是我的第一个建议:不使用stringstream吗。虽然一开始它看起来使用起来很简单,但您会发现如果想要健壮性和良好的错误处理,就必须做很多额外的工作。

下面是一个直觉上看起来应该有效的方法:

bool str2int (int &i, char const *s)
{
std::stringstream ss(s);
ss >> i;
if (ss.fail()) {
// not an integer
return false;
}
return true;
}

这有一个主要问题:str2int(i, "1337h4x0r")将愉快地返回true,而i将获得值1337。我们可以通过确保转换后stringstream中没有更多字符来解决这个问题:

bool str2int (int &i, char const *s)
{
char              c;
std::stringstream ss(s);
ss >> i;
if (ss.fail() || ss.get(c)) {
// not an integer
return false;
}
return true;
}

我们解决了一个问题,但还有其他几个问题。

如果字符串中的数字不是以10为底怎么办?在尝试转换之前,我们可以通过将流设置为正确的模式(例如ss << std::hex)来尝试适应其他基底。但这意味着调用者必须知道先天的的底数是什么——调用者怎么可能知道呢?打电话的人还不知道号码是多少。他们甚至不知道它是一个数字!怎么能指望他们知道基地是什么?我们可以强制所有输入到程序中的数字必须以10为基数,并将十六进制或八进制输入视为无效而拒绝。但这不是很灵活,也不是很稳健。这个问题没有简单的解决办法。您不能简单地为每个进制尝试一次转换,因为十进制转换对于八进制数(前导为零)总是成功的,而八进制转换对于某些十进制数可能成功。现在你要检查前导是否为0。但是等等!十六进制数也可以以0开头(0x…)。叹息。

即使你成功地处理了上面的问题,还有另一个更大的问题:如果调用者需要区分错误的输入(例如。"123foo")和超出int范围的数字(例如。“4000000000”为32位int)?对于stringstream,没有办法进行这种区分。我们只知道皈依成功还是失败。如果它失败了,我们无法知道为什么它失败了。正如你所看到的,如果你想要健壮性和清晰的错误处理,stringstream还有很多需要改进的地方。

这就引出了我的第二条建议:不使用Boost的lexical_cast。想想lexical_cast文档是怎么说的:

其中控制程度较高 要求转换, std:: stringstream和 Std::wstringstream提供更多 适当的路径。在哪里 非基于流的转换是 Required, lexical_cast是错误的 工作的工具,而不是

.

.

什么? ?我们已经看到stringstream的控制级别很差,但是它说如果你需要“更高级别的控制”,应该使用stringstream而不是lexical_cast。此外,由于lexical_cast只是stringstream的包装,它也会遇到与stringstream相同的问题:对多个数字基数的支持较差,错误处理能力较差。

最好的解决方案

幸运的是,有人已经解决了上述所有问题。C标准库包含strtol和family,它们不存在这些问题。

enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };


STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long  l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}

对于处理所有错误情况并支持从2到36的任何基数的东西来说,这非常简单。如果base为0(默认值),它将尝试从任何基数进行转换。或者调用者可以提供第三个参数,并指定只对特定的基数进行转换。它是健壮的,用最少的努力处理所有错误。

其他喜欢strtol(和家族)的原因:

  • 它表现得更好运行时性能
  • 它引入了更少的编译时开销(其他方法从头文件中引入了近20倍的SLOC)
  • 它的结果是最小的代码大小

绝对没有理由使用其他方法。

在新的c++ 11中,有这样的函数:stoi, stol, stoll, stoul等等。

int myNr = std::stoi(myString);

它将在转换错误时抛出异常。

即使这些新函数仍然具有Dan所指出的同样的问题:它们将愉快地将字符串“11x”转换为整数“11”。

更多信息:http://en.cppreference.com/w/cpp/string/basic_string/stol

如果你有c++ 11,现在合适的解决方案是<string>中的c++整数转换函数:stoistolstoulstollstoull。当给出不正确的输入时,它们会抛出适当的异常,并在底层使用快速和小型的strto*函数。

如果您被c++的早期版本所困扰,那么在实现中模拟这些函数将是向前可移植的。

在C语言中,你可以使用int atoi (const char * str)

解析c字串str,将其内容解释为整数,该整数作为int类型的值返回。

我喜欢丹·莫尔丁的回答,我将添加一点c++风格:

#include <cstdlib>
#include <cerrno>
#include <climits>
#include <stdexcept>


int to_int(const std::string &s, int base = 0)
{
char *end;
errno = 0;
long result = std::strtol(s.c_str(), &end, base);
if (errno == ERANGE || result > INT_MAX || result < INT_MIN)
throw std::out_of_range("toint: string is out of range");
if (s.length() == 0 || *end != '\0')
throw std::invalid_argument("toint: invalid string");
return result;
}

通过隐式转换,它对std::string和const char*都有效。它也适用于基数转换,例如所有to_int("0x7b")to_int("0173")to_int("01111011", 2)to_int("0000007B", 16)to_int("11120", 3)to_int("3L", 34);将返回123。

std::stoi不同,它在pre- c++ 11中工作。与std::stoiboost::lexical_caststringstream不同的是,它会为“123hohoho”这样的奇怪字符串抛出异常。

注意:此函数允许前导空格,但不允许尾随空格,即to_int(" 123")返回123,而to_int("123 ")抛出异常。确保这对于您的用例是可接受的,或者调整代码。

这样的功能可能是STL的一部分…

您可以使用这个已定义的方法。

#define toInt(x) {atoi(x.c_str())};

如果要将String转换为Integer,只需执行以下操作。

int main()
{
string test = "46", test2 = "56";
int a = toInt(test);
int b = toInt(test2);
cout<<a+b<<endl;
}

输出是102。

我知道这是一个老问题,但我已经遇到过很多次了,到目前为止,仍然没有找到一个具有以下特征的良好模板解决方案:

  • 可以转换任何基(并检测基类型)
  • 将检测错误的数据(即确保整个字符串,更少的前导/尾随空格,被转换消耗)
  • 将确保无论转换为哪种类型,字符串值的范围都是可接受的。

这是我的,带着测试带。因为它在底层使用C函数strtoull/strtoll,所以它总是首先转换为可用的最大类型。然后,如果您没有使用最大的类型,它将执行额外的范围检查,以验证您的类型没有过度(不足)流动。因此,它的性能比正确选择strtol/strtoul要差一些。然而,它也适用于short /char,据我所知,没有标准的库函数也能做到这一点。

享受;希望有人觉得它有用。

#include <cstdlib>
#include <cerrno>
#include <limits>
#include <stdexcept>
#include <sstream>


static const int DefaultBase = 10;


template<typename T>
static inline T CstrtoxllWrapper(const char *str, int base = DefaultBase)
{
while (isspace(*str)) str++; // remove leading spaces; verify there's data
if (*str == '\0') { throw std::invalid_argument("str; no data"); } // nothing to convert


// NOTE:  for some reason strtoull allows a negative sign, we don't; if
//          converting to an unsigned then it must always be positive!
if (!std::numeric_limits<T>::is_signed && *str == '-')
{ throw std::invalid_argument("str; negative"); }


// reset errno and call fn (either strtoll or strtoull)
errno = 0;
char *ePtr;
T tmp = std::numeric_limits<T>::is_signed ? strtoll(str, &ePtr, base)
: strtoull(str, &ePtr, base);


// check for any C errors -- note these are range errors on T, which may
//   still be out of the range of the actual type we're using; the caller
//   may need to perform additional range checks.
if (errno != 0)
{
if (errno == ERANGE) { throw std::range_error("str; out of range"); }
else if (errno == EINVAL) { throw std::invalid_argument("str; EINVAL"); }
else { throw std::invalid_argument("str; unknown errno"); }
}


// verify everything converted -- extraneous spaces are allowed
if (ePtr != NULL)
{
while (isspace(*ePtr)) ePtr++;
if (*ePtr != '\0') { throw std::invalid_argument("str; bad data"); }
}


return tmp;
}


template<typename T>
T StringToSigned(const char *str, int base = DefaultBase)
{
static const long long max = std::numeric_limits<T>::max();
static const long long min = std::numeric_limits<T>::min();


long long tmp = CstrtoxllWrapper<typeof(tmp)>(str, base); // use largest type


// final range check -- only needed if not long long type; a smart compiler
//   should optimize this whole thing out
if (sizeof(T) == sizeof(tmp)) { return tmp; }


if (tmp < min || tmp > max)
{
std::ostringstream err;
err << "str; value " << tmp << " out of " << sizeof(T) * 8
<< "-bit signed range (";
if (sizeof(T) != 1) err << min << ".." << max;
else err << (int) min << ".." << (int) max;  // don't print garbage chars
err << ")";
throw std::range_error(err.str());
}


return tmp;
}


template<typename T>
T StringToUnsigned(const char *str, int base = DefaultBase)
{
static const unsigned long long max = std::numeric_limits<T>::max();


unsigned long long tmp = CstrtoxllWrapper<typeof(tmp)>(str, base); // use largest type


// final range check -- only needed if not long long type; a smart compiler
//   should optimize this whole thing out
if (sizeof(T) == sizeof(tmp)) { return tmp; }


if (tmp > max)
{
std::ostringstream err;
err << "str; value " << tmp << " out of " << sizeof(T) * 8
<< "-bit unsigned range (0..";
if (sizeof(T) != 1) err << max;
else err << (int) max;  // don't print garbage chars
err << ")";
throw std::range_error(err.str());
}


return tmp;
}


template<typename T>
inline T
StringToDecimal(const char *str, int base = DefaultBase)
{
return std::numeric_limits<T>::is_signed ? StringToSigned<T>(str, base)
: StringToUnsigned<T>(str, base);
}


template<typename T>
inline T
StringToDecimal(T &out_convertedVal, const char *str, int base = DefaultBase)
{
return out_convertedVal = StringToDecimal<T>(str, base);
}


/*============================== [ Test Strap ] ==============================*/


#include <inttypes.h>
#include <iostream>


static bool _g_anyFailed = false;


template<typename T>
void TestIt(const char *tName,
const char *s, int base,
bool successExpected = false, T expectedValue = 0)
{
#define FAIL(s) { _g_anyFailed = true; std::cout << s; }


T x;
std::cout << "converting<" << tName << ">b:" << base << " [" << s << "]";
try
{
StringToDecimal<T>(x, s, base);
// get here on success only
if (!successExpected)
{
FAIL(" -- TEST FAILED; SUCCESS NOT EXPECTED!" << std::endl);
}
else
{
std::cout << " -> ";
if (sizeof(T) != 1) std::cout << x;
else std::cout << (int) x;  // don't print garbage chars
if (x != expectedValue)
{
FAIL("; FAILED (expected value:" << expectedValue << ")!");
}
std::cout << std::endl;
}
}
catch (std::exception &e)
{
if (successExpected)
{
FAIL(   " -- TEST FAILED; EXPECTED SUCCESS!"
<< " (got:" << e.what() << ")" << std::endl);
}
else
{
std::cout << "; expected exception encounterd: [" << e.what() << "]" << std::endl;
}
}
}


#define TEST(t, s, ...) \
TestIt<t>(#t, s, __VA_ARGS__);


int main()
{
std::cout << "============ variable base tests ============" << std::endl;
TEST(int, "-0xF", 0, true, -0xF);
TEST(int, "+0xF", 0, true, 0xF);
TEST(int, "0xF", 0, true, 0xF);
TEST(int, "-010", 0, true, -010);
TEST(int, "+010", 0, true, 010);
TEST(int, "010", 0, true, 010);
TEST(int, "-10", 0, true, -10);
TEST(int, "+10", 0, true, 10);
TEST(int, "10", 0, true, 10);


std::cout << "============ base-10 tests ============" << std::endl;
TEST(int, "-010", 10, true, -10);
TEST(int, "+010", 10, true, 10);
TEST(int, "010", 10, true, 10);
TEST(int, "-10", 10, true, -10);
TEST(int, "+10", 10, true, 10);
TEST(int, "10", 10, true, 10);
TEST(int, "00010", 10, true, 10);


std::cout << "============ base-8 tests ============" << std::endl;
TEST(int, "777", 8, true, 0777);
TEST(int, "-0111 ", 8, true, -0111);
TEST(int, "+0010 ", 8, true, 010);


std::cout << "============ base-16 tests ============" << std::endl;
TEST(int, "DEAD", 16, true, 0xDEAD);
TEST(int, "-BEEF", 16, true, -0xBEEF);
TEST(int, "+C30", 16, true, 0xC30);


std::cout << "============ base-2 tests ============" << std::endl;
TEST(int, "-10011001", 2, true, -153);
TEST(int, "10011001", 2, true, 153);


std::cout << "============ irregular base tests ============" << std::endl;
TEST(int, "Z", 36, true, 35);
TEST(int, "ZZTOP", 36, true, 60457993);
TEST(int, "G", 17, true, 16);
TEST(int, "H", 17);


std::cout << "============ space deliminated tests ============" << std::endl;
TEST(int, "1337    ", 10, true, 1337);
TEST(int, "   FEAD", 16, true, 0xFEAD);
TEST(int, "   0711   ", 0, true, 0711);


std::cout << "============ bad data tests ============" << std::endl;
TEST(int, "FEAD", 10);
TEST(int, "1234 asdfklj", 10);
TEST(int, "-0xF", 10);
TEST(int, "+0xF", 10);
TEST(int, "0xF", 10);
TEST(int, "-F", 10);
TEST(int, "+F", 10);
TEST(int, "12.4", 10);
TEST(int, "ABG", 16);
TEST(int, "10011002", 2);


std::cout << "============ int8_t range tests ============" << std::endl;
TEST(int8_t, "7F", 16, true, std::numeric_limits<int8_t>::max());
TEST(int8_t, "80", 16);
TEST(int8_t, "-80", 16, true, std::numeric_limits<int8_t>::min());
TEST(int8_t, "-81", 16);
TEST(int8_t, "FF", 16);
TEST(int8_t, "100", 16);


std::cout << "============ uint8_t range tests ============" << std::endl;
TEST(uint8_t, "7F", 16, true, std::numeric_limits<int8_t>::max());
TEST(uint8_t, "80", 16, true, std::numeric_limits<int8_t>::max()+1);
TEST(uint8_t, "-80", 16);
TEST(uint8_t, "-81", 16);
TEST(uint8_t, "FF", 16, true, std::numeric_limits<uint8_t>::max());
TEST(uint8_t, "100", 16);


std::cout << "============ int16_t range tests ============" << std::endl;
TEST(int16_t, "7FFF", 16, true, std::numeric_limits<int16_t>::max());
TEST(int16_t, "8000", 16);
TEST(int16_t, "-8000", 16, true, std::numeric_limits<int16_t>::min());
TEST(int16_t, "-8001", 16);
TEST(int16_t, "FFFF", 16);
TEST(int16_t, "10000", 16);


std::cout << "============ uint16_t range tests ============" << std::endl;
TEST(uint16_t, "7FFF", 16, true, std::numeric_limits<int16_t>::max());
TEST(uint16_t, "8000", 16, true, std::numeric_limits<int16_t>::max()+1);
TEST(uint16_t, "-8000", 16);
TEST(uint16_t, "-8001", 16);
TEST(uint16_t, "FFFF", 16, true, std::numeric_limits<uint16_t>::max());
TEST(uint16_t, "10000", 16);


std::cout << "============ int32_t range tests ============" << std::endl;
TEST(int32_t, "7FFFFFFF", 16, true, std::numeric_limits<int32_t>::max());
TEST(int32_t, "80000000", 16);
TEST(int32_t, "-80000000", 16, true, std::numeric_limits<int32_t>::min());
TEST(int32_t, "-80000001", 16);
TEST(int32_t, "FFFFFFFF", 16);
TEST(int32_t, "100000000", 16);


std::cout << "============ uint32_t range tests ============" << std::endl;
TEST(uint32_t, "7FFFFFFF", 16, true, std::numeric_limits<int32_t>::max());
TEST(uint32_t, "80000000", 16, true, std::numeric_limits<int32_t>::max()+1);
TEST(uint32_t, "-80000000", 16);
TEST(uint32_t, "-80000001", 16);
TEST(uint32_t, "FFFFFFFF", 16, true, std::numeric_limits<uint32_t>::max());
TEST(uint32_t, "100000000", 16);


std::cout << "============ int64_t range tests ============" << std::endl;
TEST(int64_t, "7FFFFFFFFFFFFFFF", 16, true, std::numeric_limits<int64_t>::max());
TEST(int64_t, "8000000000000000", 16);
TEST(int64_t, "-8000000000000000", 16, true, std::numeric_limits<int64_t>::min());
TEST(int64_t, "-8000000000000001", 16);
TEST(int64_t, "FFFFFFFFFFFFFFFF", 16);
TEST(int64_t, "10000000000000000", 16);


std::cout << "============ uint64_t range tests ============" << std::endl;
TEST(uint64_t, "7FFFFFFFFFFFFFFF", 16, true, std::numeric_limits<int64_t>::max());
TEST(uint64_t, "8000000000000000", 16, true, std::numeric_limits<int64_t>::max()+1);
TEST(uint64_t, "-8000000000000000", 16);
TEST(uint64_t, "-8000000000000001", 16);
TEST(uint64_t, "FFFFFFFFFFFFFFFF", 16, true, std::numeric_limits<uint64_t>::max());
TEST(uint64_t, "10000000000000000", 16);


std::cout << std::endl << std::endl
<< (_g_anyFailed ? "!! SOME TESTS FAILED !!" : "ALL TESTS PASSED")
<< std::endl;


return _g_anyFailed;
}

StringToDecimal是user-land方法;它是重载的,所以可以像这样调用它:

int a; a = StringToDecimal<int>("100");

或:

int a; StringToDecimal(a, "100");

我讨厌重复int类型,所以更喜欢后者。这确保了如果“a”的类型发生了变化,也不会得到不好的结果。我希望编译器能像这样计算出来:

int a; a = StringToDecimal("100");

...但是,c++不推导模板返回类型,所以这是我能得到的最好的。

实现非常简单:

CstrtoxllWrapper包装了strtoullstrtoll,根据模板类型的有符号性调用任何必要的类型,并提供一些额外的保证(例如,如果无符号,则不允许负输入,并确保整个字符串被转换)。

CstrtoxllWrapperStringToSignedStringToUnsigned使用,具有编译器可用的最大类型(long long/unsigned long long);这允许执行最大的转换。然后,如果有必要,StringToSigned/StringToUnsigned对底层类型执行最后的范围检查。最后,端点方法StringToDecimal根据底层类型的符号性决定调用哪一个StringTo*模板方法。

我认为大多数垃圾可以被编译器优化掉;几乎所有东西都应该是编译时确定的。任何关于这方面的评论对我来说都很有趣!

我喜欢丹的回答,尤其是因为它避免了异常。对于嵌入式系统开发和其他低级别的系统开发,可能没有适当的Exception框架可用。

增加了一个有效字符串后的空白检查…这三行

    while (isspace(*end)) {
end++;
}
< p > < br >

    if ((errno != 0) || (s == end)) {
return INCONVERTIBLE;
}
< p > < br > 下面是完整的函数..

#include <cstdlib>
#include <cerrno>
#include <climits>
#include <stdexcept>


enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };


STR2INT_ERROR str2long (long &l, char const *s, int base = 0)
{
char *end = (char *)s;
errno = 0;


l = strtol(s, &end, base);


if ((errno == ERANGE) && (l == LONG_MAX)) {
return OVERFLOW;
}
if ((errno == ERANGE) && (l == LONG_MIN)) {
return UNDERFLOW;
}
if ((errno != 0) || (s == end)) {
return INCONVERTIBLE;
}
while (isspace((unsigned char)*end)) {
end++;
}


if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}


return SUCCESS;
}

我知道三种将String转换为int的方法:

要么使用stoi(String to int)函数,要么使用Stringstream,第三种方式进行个人转换,代码如下:

1号方法

std::string s1 = "4533";
std::string s2 = "3.010101";
std::string s3 = "31337 with some string";


int myint1 = std::stoi(s1);
int myint2 = std::stoi(s2);
int myint3 = std::stoi(s3);


std::cout <<  s1 <<"=" << myint1 << '\n';
std::cout <<  s2 <<"=" << myint2 << '\n';
std::cout <<  s3 <<"=" << myint3 << '\n';

2方法

#include <string.h>
#include <sstream>
#include <iostream>
#include <cstring>
using namespace std;




int StringToInteger(string NumberAsString)
{
int NumberAsInteger;
stringstream ss;
ss << NumberAsString;
ss >> NumberAsInteger;
return NumberAsInteger;
}
int main()
{
string NumberAsString;
cin >> NumberAsString;
cout << StringToInteger(NumberAsString) << endl;
return 0;
}

第三种方法-但不是个人转换

std::string str4 = "453";
int i = 0, in=0; // 453 as on
for ( i = 0; i < str4.length(); i++)
{


in = str4[i];
cout <<in-48 ;


}

从c++ 17开始,你可以从<charconv>头文件中使用std::from_chars,如文档中的在这里

例如:

#include <iostream>
#include <charconv>
#include <array>


int main()
{
char const * str = "42";
int value = 0;


std::from_chars_result result = std::from_chars(std::begin(str), std::end(str), value);


if(result.error == std::errc::invalid_argument)
{
std::cout << "Error, invalid format";
}
else if(result.error == std::errc::result_out_of_range)
{
std::cout << "Error, value too big for int range";
}
else
{
std::cout << "Success: " << result;
}
}

另外,它还可以处理其他进制,比如十六进制。