c++用什么方法把字符串(char *)解析成int?健壮和清晰的错误处理是一个加分项(而不是返回0)。
传统的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
我认为这三个环节可以概括:
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中没有更多字符来解决这个问题:
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…)。叹息。
ss << std::hex
即使你成功地处理了上面的问题,还有另一个更大的问题:如果调用者需要区分错误的输入(例如。"123foo")和超出int范围的数字(例如。“4000000000”为32位int)?对于stringstream,没有办法进行这种区分。我们只知道皈依成功还是失败。如果它失败了,我们无法知道为什么它失败了。正如你所看到的,如果你想要健壮性和清晰的错误处理,stringstream还有很多需要改进的地方。
int
这就引出了我的第二条建议:不使用Boost的lexical_cast。想想lexical_cast文档是怎么说的:
其中控制程度较高 要求转换, std:: stringstream和 Std::wstringstream提供更多 适当的路径。在哪里 非基于流的转换是 Required, lexical_cast是错误的 工作的工具,而不是 . .
其中控制程度较高 要求转换, std:: stringstream和 Std::wstringstream提供更多 适当的路径。在哪里 非基于流的转换是 Required, lexical_cast是错误的 工作的工具,而不是
什么? ?我们已经看到stringstream的控制级别很差,但是它说如果你需要“更高级别的控制”,应该使用stringstream而不是lexical_cast。此外,由于lexical_cast只是stringstream的包装,它也会遇到与stringstream相同的问题:对多个数字基数的支持较差,错误处理能力较差。
幸运的是,有人已经解决了上述所有问题。C标准库包含strtol和family,它们不存在这些问题。
strtol
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(默认值),它将尝试从任何基数进行转换。或者调用者可以提供第三个参数,并指定只对特定的基数进行转换。它是健壮的,用最少的努力处理所有错误。
base
其他喜欢strtol(和家族)的原因:
绝对没有理由使用其他方法。
在新的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++整数转换函数:stoi, stol, stoul, stoll, stoull。当给出不正确的输入时,它们会抛出适当的异常,并在底层使用快速和小型的strto*函数。
<string>
stoi
stol
stoul
stoll
stoull
strto*
如果您被c++的早期版本所困扰,那么在实现中模拟这些函数将是向前可移植的。
在C语言中,你可以使用int atoi (const char * str),
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。
to_int("0x7b")
to_int("0173")
to_int("01111011", 2)
to_int("0000007B", 16)
to_int("11120", 3)
to_int("3L", 34);
与std::stoi不同,它在pre- c++ 11中工作。与std::stoi、boost::lexical_cast和stringstream不同的是,它会为“123hohoho”这样的奇怪字符串抛出异常。
std::stoi
boost::lexical_cast
注意:此函数允许前导空格,但不允许尾随空格,即to_int(" 123")返回123,而to_int("123 ")抛出异常。确保这对于您的用例是可接受的,或者调整代码。
to_int(" 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方法;它是重载的,所以可以像这样调用它:
StringToDecimal
int a; a = StringToDecimal<int>("100");
或:
int a; StringToDecimal(a, "100");
我讨厌重复int类型,所以更喜欢后者。这确保了如果“a”的类型发生了变化,也不会得到不好的结果。我希望编译器能像这样计算出来:
int a; a = StringToDecimal("100");
...但是,c++不推导模板返回类型,所以这是我能得到的最好的。
实现非常简单:
CstrtoxllWrapper包装了strtoull和strtoll,根据模板类型的有符号性调用任何必要的类型,并提供一些额外的保证(例如,如果无符号,则不允许负输入,并确保整个字符串被转换)。
CstrtoxllWrapper
strtoull
strtoll
CstrtoxllWrapper由StringToSigned和StringToUnsigned使用,具有编译器可用的最大类型(long long/unsigned long long);这允许执行最大的转换。然后,如果有必要,StringToSigned/StringToUnsigned对底层类型执行最后的范围检查。最后,端点方法StringToDecimal根据底层类型的符号性决定调用哪一个StringTo*模板方法。
StringToSigned
StringToUnsigned
我认为大多数垃圾可以被编译器优化掉;几乎所有东西都应该是编译时确定的。任何关于这方面的评论对我来说都很有趣!
我喜欢丹的回答,尤其是因为它避免了异常。对于嵌入式系统开发和其他低级别的系统开发,可能没有适当的Exception框架可用。
增加了一个有效字符串后的空白检查…这三行
while (isspace(*end)) { end++; }
if ((errno != 0) || (s == end)) { return INCONVERTIBLE; }
#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,如文档中的在这里。
<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; } }
另外,它还可以处理其他进制,比如十六进制。