How to parse a string to an int in C++?
将字符串解析(以char *形式)转换成int的C++方式是什么?稳健和清晰的错误处理是一个优点(而不是返回零)。
不该做什么
这是我的第一条建议:不要使用Stringstream。虽然起初使用起来似乎很简单,但如果您希望健壮性和良好的错误处理,那么您将发现需要做很多额外的工作。
这是一种直观的方法,它看起来应该有效:
1 2 3 4 5 6 7 8 9 10 | bool str2int (int &i, char const *s) { std::stringstream ss(s); ss >> i; if (ss.fail()) { // not an integer return false; } return true; } |
这有一个大问题:
1 2 3 4 5 6 7 8 9 10 11 | 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为基数怎么办?在尝试转换之前,我们可以通过将流设置为正确的模式(例如
即使您成功地处理了上述问题,仍然存在另一个更大的问题:如果调用者需要区分坏输入(如"123foo")和超出
这就引出了我的第二条建议:不要用Boost的
Where a higher degree of control is
required over conversions,
std::stringstream and
std::wstringstream offer a more
appropriate path. Where
non-stream-based conversions are
required, lexical_cast is the wrong
tool for the job and is not
special-cased for such scenarios.
什么??我们已经看到
幸运的是,已经有人解决了上述所有问题。C标准库包含没有这些问题的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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的任何基数的东西来说,这非常简单。如果
选择
- 它显示出更好的运行时性能
- 它引入的编译时间开销更少(其他的从头中引入的sloc比它多近20倍)
- 它产生最小的代码大小
完全没有理由使用任何其他方法。
在新的C++ 11中,函数有:Stoi、Stol、Stol、Stoul等。
1 | int myNr = std::stoi(myString); |
它将在转换错误时引发异常。
即使是这些新函数,仍然存在与dan所指出的相同的问题:它们将很高兴地将字符串"11x"转换为整数"11"。
更多信息请参见:http://en.cppreference.com/w/cpp/string/basic_string/stol
这是比ATOI()更安全的C方法
1 2 3 4 5 6 7 | const char* str ="123"; int i; if(sscanf(str,"%d", &i) == EOF ) { /* error */ } |
C++与标准库STRIGSTROW:(谢谢CMS)
1 2 3 4 5 6 7 8 9 | int str2int (const string &str) { stringstream ss(str); int num; if((ss >> num).fail()) { //ERROR } return num; } |
带Boost库:(谢谢JK)
1 2 3 4 5 6 7 8 9 10 11 12 | #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对原始帖子的评论)
您可以使用Boost的
好的"老C"方法仍然有效。我推荐Strtol或Strtoul。在返回状态和"endptr"之间,可以提供良好的诊断输出。它还可以很好地处理多个基地。
您可以使用C++标准库中的A股流:
1 2 3 4 5 6 7 8 9 | stringstream ss(str); int x; ss >> x; if(ss) { // <-- error handling // use x } else { // not a number } |
The stream state will be set to fail
if a non-digit is encountered when
trying to read an integer.
请参阅流错误的错误处理和流在C++中的陷阱。
可以使用Stringstream的
1 2 3 4 5 6 | int str2int (const string &str) { stringstream ss(str); int num; ss >> num; return num; } |
我认为这三个环节总结如下:
- http://tinodidriksen.com/2010/02/07/cpp-convert-int-to-string-speed/
- http://tinodidriksen.com/2010/02/16/cpp-convert-string-to-int-speed/
- http://www.fastformat.org/performance.html
Stringstream和Lexical-Cast解决方案与Lexical-Cast使用Stringstream的解决方案大致相同。
词法转换的某些专门化使用不同的方法。有关详细信息,请参阅http://www.boost.org/doc/libs/release/boost/lexical_cast.hpp。整数和浮点数现在专门用于整数到字符串的转换。
你可以根据自己的需要专门制作词汇表,并使之快速。这将是让各方满意的最终解决方案,既干净又简单。
已经提到的文章显示了不同的整数转换方法<->字符串之间的比较。以下方法是有意义的:旧的c-way,spirit.karma,fastformat,简单的天真循环。
词法转换在某些情况下是可以的,例如int到string转换。
使用词汇转换将字符串转换为int不是一个好主意,因为它比ATOI慢10-40倍,这取决于所使用的平台/编译器。
karma似乎是将整数转换为字符串的最快库。
1 | ex.: generate(ptr_char, int_, integer_number); |
上面文章中的基本简单循环是将字符串转换为int的最快方法,显然不是最安全的方法,strtol()似乎是更安全的解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } |
C++字符串工具包库(STRTK)具有以下解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | 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可以是无符号char*、char*或std::string迭代器,t应该是有符号int,如signed int、int或long。
如果你有C++ 11,现在适当的解决方案是EDCOX1中的C++整数转换函数:0:EDOCX1,1,EDOCX1,2,EDCOX1,3,EDCOX1,4,EDOCX1 5。当输入错误时,它们会抛出适当的异常,并使用发动机罩下的快速和小型
如果你被C++的早期修订所困扰,那么在你的实现中模拟这些函数将会是你的一种可移植性。
从C++ 17开始,您可以使用EDCOX1,0,EDCX1,1的头,如这里所记录的。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <iostream> #include <charconv> #include 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; } } |
作为一个额外的好处,它还可以处理其他基,比如十六进制。
我喜欢Dan Moulding的答案,我只想给它添加一点C++风格:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #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*。它还可用于基础转换,例如,所有
与
注意:此函数允许前导空格而不允许尾随空格,即
这种功能可能是STL的一部分。
我知道将字符串转换为int的三种方法:
要么使用stoi(string to int)函数,要么只使用stringstream,这是进行单个转换的第三种方法,代码如下:
第一方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 << ' '; std::cout << s2 <<"=" << myint2 << ' '; std::cout << s3 <<"=" << myint3 << ' '; |
第二方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #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; } |
第三种方法-但不适用于单个转换
1 2 3 4 5 6 7 8 9 | 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 ; } |
我喜欢丹的回答,尤其是因为避免了例外。对于嵌入式系统开发和其他低级系统开发,可能没有合适的异常框架可用。
在有效字符串后添加了一个空白检查…这三行
1 2 3 | while (isspace(*end)) { end++; } |
还添加了分析错误的检查。
1 2 3 | if ((errno != 0) || (s == end)) { return INCONVERTIBLE; } |
这是完整的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #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; } |
我知道这是一个老问题,但我已经遇到过很多次了,到目前为止,还没有找到一个具有以下特征的模板化解决方案:
- 可以转换任何基(并检测基类型)
- 将检测错误的数据(即,确保整个字符串(少于前导/尾随空格)被转换消耗)
- 将确保,无论转换为何种类型,字符串值的范围都是可接受的。
所以,这是我的,带着测试带。因为它在引擎盖下使用C函数strtoull/strtoll,所以它总是首先转换为可用的最大类型。然后,如果您没有使用最大的类型,它将执行额外的范围检查,以验证您的类型没有溢出(不足)。因此,它的性能比正确选择strtol/strtoul要差一点。但是,它也适用于short/chars,据我所知,也没有标准的库函数可以做到这一点。
享受;希望有人发现它有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | #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; } |
1 | int a; a = StringToDecimal<int>("100"); |
或者:
1 | int a; StringToDecimal(a,"100"); |
我讨厌重复int类型,所以更喜欢后者。这样可以确保,如果"a"的类型发生更改,不会得到坏的结果。我希望编译器能像这样理解它:
1 | int a; a = StringToDecimal("100"); |
但是,C++没有演绎模板返回类型,所以这是我能得到的最好的。
实现非常简单:
我认为大多数垃圾都可以通过编译器进行优化;几乎所有东西都应该是编译时确定性的。任何关于这方面的评论对我来说都是有趣的!
您可以使用这个定义的方法。
1 | #define toInt(x) {atoi(x.c_str())}; |
如果要将字符串转换为整数,只需执行以下操作。
1 2 3 4 5 6 7 | int main() { string test ="46", test2 ="56"; int a = toInt(test); int b = toInt(test2); cout<<a+b<<endl; } |
输出为102。
在C语言中,可以使用
解析C-string str,将其内容解释为整数,该整数作为int类型的值返回。