将字符串(以char *形式给出)解析为int的C ++方法是什么?强大而清晰的错误处理是一个加号(而不是returning zero)。
答案 0 :(得分:197)
这是我的第一条建议:不要使用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,并拒绝十六进制或八进制输入为无效。但这不是非常灵活或强大。这个问题没有简单的解决方案。你不能简单地为每个基数尝试一次转换,因为对于八进制数字(前导零),十进制转换将始终成功,并且对于某些十进制数字,八进制转换可能会成功。所以现在你必须检查一个前导零。可是等等!十六进制数也可以从前导零开始(0x ...)。叹息。
即使您成功处理上述问题,仍然存在另一个更大的问题:如果调用者需要区分错误输入(例如“123foo”)和超出{{1范围的数字(例如“4000000000”用于32位int
)?使用int
,无法进行此区分。我们只知道转换是成功还是失败。如果失败,我们无法知道为什么失败。正如您所看到的,如果您需要健壮性和清晰的错误处理,stringstream
还有很多不足之处。
这引出了我的第二条建议:不要使用Boost的stringstream
来实现这个。考虑lexical_cast
文档所说的内容:
更高程度的控制 需要转换, std :: stringstream和 std :: wstringstream提供更多 适当的路径。哪里 基于非流的转换是 必需的,lexical_cast是错误的 工作的工具,而不是 这种情况特别适用。
什么?我们已经看到lexical_cast
的控制级别很差,但是如果您需要“更高级别的控制”,则应该使用stringstream
代替stringstream
。另外,因为lexical_cast
只是lexical_cast
的包装,所以它会遇到与stringstream
相同的问题:对多个数字基础的支持不足以及错误处理不佳。
幸运的是,有人已经解决了上述所有问题。 C标准库包含stringstream
和系列,没有这些问题。
strtol
对于处理所有错误情况并且还支持从2到36的任何数字基础的东西非常简单。如果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;
}
为零(默认值),它将尝试从任何基数转换。或者调用者可以提供第三个参数,并指定只应针对特定的基础进行转换。它非常强大,只需很少的工作量即可处理所有错误。
偏好base
(和家人)的其他原因:
绝对没有充分的理由使用任何其他方法。
答案 1 :(得分:154)
在新的C ++ 11中有以下功能:stoi,stol,stoll,stoul等。
int myNr = std::stoi(myString);
它会在转换错误上抛出异常。
即使这些新功能仍然存在Dan所指出的相同问题:他们会很乐意将字符串“11x”转换为整数“11”。
查看更多:http://en.cppreference.com/w/cpp/string/basic_string/stol
答案 2 :(得分:67)
这比atoi()
更安全const char* str = "123";
int i;
if(sscanf(str, "%d", &i) == EOF )
{
/* error */
}
标准库stringstream的C ++ :(感谢CMS)
int str2int (const string &str) {
stringstream ss(str);
int num;
if((ss >> num).fail())
{
//ERROR
}
return num;
}
#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
}
编辑:修复了字符串流版本,以便处理错误。 (感谢CMS和jk对原帖的评论)
答案 3 :(得分:22)
您可以在更通用的界面中使用Boost's lexical_cast
wraps this。
lexical_cast<Target>(Source)
在失败时抛出bad_lexical_cast
。
答案 4 :(得分:21)
良好的'老C方式仍然有效。我推荐strtol或strtoul。在返回状态和'endPtr'之间,您可以提供良好的诊断输出。它还可以很好地处理多个基础。
答案 5 :(得分:16)
您可以使用C ++标准库中的字符串流:
stringstream ss(str);
int x;
ss >> x;
if(ss) { // <-- error handling
// use x
} else {
// not a number
}
流状态将设置为失败 如果遇到非数字 试图读取整数。
请参阅Stream pitfalls,了解C ++中错误处理和流的缺陷。
答案 6 :(得分:10)
您可以使用stringstream's
int str2int (const string &str) {
stringstream ss(str);
int num;
ss >> num;
return num;
}
答案 7 :(得分:7)
我认为这三个链接总结了一下:
stringstream和lexical_cast解决方案与使用stringstream的lexical cast大致相同。
词法演员的一些专业化使用不同的方法,请参阅 http://www.boost.org/doc/libs/release/boost/lexical_cast.hpp 了解详情。整数和浮点数现在专门用于整数到字符串的转换。
可以根据自己的需要专门研究lexical_cast并快速完成。这将是满足所有各方的最终解决方案,简洁明了。
已经提到的文章显示了转换整数的不同方法之间的比较&lt; - &gt;字符串。以下方法有意义:旧的c-way,spirit.karma,fastformat,简单的天真循环。
Lexical_cast在某些情况下是可以的,例如用于int到字符串的转换。
使用lexical cast将字符串转换为int不是一个好主意,因为它比atoi慢10-40倍,具体取决于所使用的平台/编译器。
Boost.Spirit.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;
}
答案 8 :(得分:7)
C++ String Toolkit Library (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
答案 9 :(得分:6)
如果你有C ++ 11,现在适当的解决方案是<string>
中的C ++整数转换函数:stoi
,stol
,stoul
,{{1} },stoll
。如果给出错误的输入,它们会抛出适当的异常,并使用引擎盖下的快速和小stoull
函数。
如果您坚持使用早期版本的C ++,那么在您的实现中模仿这些函数将是您的前瞻性。
答案 10 :(得分:5)
从C ++ 17开始,您可以使用std::from_chars
标题<charconv>
中的#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;
}
}
。
例如:
KafkaConsumer<String, byte[]> consum = new KafkaConsumer<String, byte[]>(props);
ConsumerRecords<String, byte[]> records = kconsumer.poll(timeoutInMS);
作为奖励,它还可以处理其他基础,例如十六进制。
答案 11 :(得分:2)
我喜欢Dan Moulding's answer,我只想添加一些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::stoi
,boost::lexical_cast
和stringstream
不同,它会抛出像“123hohoho”这样的奇怪字符串的异常。
注意:此函数容忍前导空格但不容许尾随空格,即to_int(" 123")
返回123而to_int("123 ")
抛出异常。确保这对您的用例是可接受的或调整代码。
此类功能可能是STL的一部分......
答案 12 :(得分:2)
我知道将String转换为int的三种方法:
使用stoi(String to int)函数或者只使用Stringstream,第三种方式进行单独转换,代码如下:
第一种方法
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';
第二种方法
#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 ;
}
答案 13 :(得分:1)
我喜欢Dan's answer,因为避免了异常。对于嵌入式系统开发和其他低级系统开发,可能没有适当的异常框架可用。
在有效字符串后添加了对空格的检查......这三行
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;
}
这是完整的功能..
Color.BLUE
答案 14 :(得分:0)
您可以使用此定义的方法。
#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。
答案 15 :(得分:0)
我知道这是一个较老的问题,但我已经多次遇到它,到目前为止,仍然没有找到具有以下特征的精心模板解决方案:
所以,这是我的,带有测试带。因为它在引擎盖下使用了C函数strtoull / strtoll,所以它总是首先转换为可用的最大类型。然后,如果您没有使用最大类型,它将执行额外的范围检查以验证您的类型未超过(下)流动。对于这个,它比正确选择strtol / strtoul要差一点。但是,它也适用于短路/字符,据我所知,也没有标准的库函数可以做到这一点。
享受;希望有人发现它很有用。
#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
是用户土地方法;它被重载所以它可以这样调用:
int a; a = StringToDecimal<int>("100");
或者这个:
int a; StringToDecimal(a, "100");
我讨厌重复int类型,所以更喜欢后者。这确保了如果&#39; a&#39;改变一个不会得到不好的结果。我希望编译器可以解决它:
int a; a = StringToDecimal("100");
...但是,C ++并没有推断出模板返回类型,因此这是我能得到的最好的。
实施非常简单:
CstrtoxllWrapper
包含strtoull
和strtoll
,根据模板类型的签名调用任何必要的内容,并提供一些额外的保证(例如,如果不提供负输入,则不允许unsigned,它确保整个字符串被转换。)
CstrtoxllWrapper
和StringToSigned
使用 StringToUnsigned
,编译器可以使用最大类型(long long / unsigned long long);这允许执行最大转换。然后,如果有必要,StringToSigned
/ StringToUnsigned
将对基础类型执行最终范围检查。最后,端点方法StringToDecimal
根据基础类型的签名来决定调用哪个StringTo *模板方法。
我认为大多数垃圾都可以通过编译器进行优化;几乎所有东西都应该是编译时确定性的。关于这方面的任何评论对我来说都很有趣!
答案 16 :(得分:-3)
在C中,您可以使用int atoi (const char * str)
,
解析C-string str将其内容解释为整数,该值作为int类型的值返回。