Определить, будет ли число (закодированное в виде строки) соответствовать 64-разрядному целому числу в C++?
Я ищу портативный способ а) преобразовать строку в 64-разрядное целое число со знаком (int64_t) и б) определить, если он не подходит (переполнения). Есть какой-либо способ сделать это?
5 ответов
Основываясь на полезном ответе Джошуа Глейзера, я пришел к следующему решению, которое выполняет проверку ошибок, а также работает для отрицательных целых чисел:
#define __STDC_LIMIT_MACROS
#include <stdint.h>
// convert a string to an integer, return whether successful
bool string_to_int(string in, int64_t &out) {
size_t pos = 0;
if (in.size() == 0)
return false;
if (in[pos] == '+')
pos++;
out = 0;
if (in[pos] == '-') {
pos++;
while (pos < in.size()) {
if (in[pos] < '0' || in[pos] > '9')
return false;
int c = in[pos]-'0';
if (out < (INT64_MIN+c)/10)
return false;
out = out*10-c;
pos++;
}
} else {
while (pos < in.size()) {
if (in[pos] < '0' || in[pos] > '9')
return false;
int c = in[pos]-'0';
if (out > (INT64_MAX-c)/10)
return false;
out = out*10+c;
pos++;
}
}
return true;
}
strtoll
больше портативен И если не в вашем случае, вы всегда можете написать библиотеку времени выполнения GNU C и добавить ее в свой проект...
errno = 0;
long long val = strtoll (string, NULL, 0);
if (errno == ERANGE)
// there was an overflow conversion error
Пробежитесь по символам строки по одному и сделайте ваше целое число. если анализируемый символ вызовет переполнение, то вы знаете, что собираетесь переполниться. этот код является основной идеей - он не обрабатывает ошибки или отрицательные числа, но должен дать вам идею...
bool ConvertToInt( const char* inString, int64_t& outInt )
{
int64_t kInt64Max = 0x7fffffffffffffff;
const char* c = inString;
outInt = 0;
while( *c != '\0' )
{
int charValue = *c - '0';
//outInt will be assigned outInt * 10 + charValue, so to check if that will overflow
//use algebra and move stuff around so that you can do the math without overflowing
if( outInt > ( kInt64Max - charValue ) / 10 )
{
//overflow
return false;
}
outInt = outInt * 10 + charValue;
++c;
}
return true;
}
если вы хотите получить полную оценку за домашнее задание, не забудьте обработать отрицательные числа и нечисловые символы. [Отредактировано для увеличения c ptr- спасибо за подсказку:))
Для обслуживания Visual C++ 10.0 (как я пишу этот 11.0 находится в бета-версии), который, по-видимому, не имеет strtoll
или любой другой эквивалент,
#include <assert.h> // assert
#include <errno.h> // errno
#include <stdint.h> // int64_t
#include <string> // std::string
#include <stdexcept> // std::runtime_error, std::range_error
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS, strtoll
#include <iostream>
using namespace std;
#if defined( _MSC_VER )
# if _MSC_VER <= 1600
# include <ole2.h>
inline long long strtoll( char const *str, char **str_end, int base )
{
assert(( "Only base 10 for Visual C++ 10 and earlier", base == 10 ));
std::wstring const ws( str, str + strlen( str ) );
LONG64 result;
HRESULT const hr = VarI8FromStr(
ws.c_str(), 0, LOCALE_NOUSEROVERRIDE, &result
);
switch( hr )
{
case S_OK:
if( str_end != 0 )
{
*str_end = const_cast<char*>( str + strlen( str ) );
}
return result;
case DISP_E_OVERFLOW:
errno = ERANGE;
if( str_end != 0 )
{
*str_end = const_cast<char*>( str );
}
return (*str == '-'? LLONG_MIN : LLONG_MAX);
default:
errno = EILSEQ;
if( str_end != 0 )
{
*str_end = const_cast<char*>( str );
}
return 0;
}
}
# endif
#endif
template< class Type >
bool hopefully( Type const& v ) { return !!v; }
bool throwX( string const& s ) { throw runtime_error( s ); }
bool throwRangeX( string const& s ) { throw range_error( s ); }
int64_t int64From( string const& s )
{
errno = 0;
int64_t const result = strtoll( s.c_str(), nullptr, 10 );
if( errno == ERANGE )
throwRangeX( "int64From: specificed nr too large" );
else if( errno != 0 )
throwX( "int64From: parsing failed" );
return result;
}
int main( int argc, char** argv )
{
try
{
int64_t const x = int64From( argv[argc - 1] );
wcout << x << endl;
return EXIT_SUCCESS;
}
catch( runtime_error const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
Затем для Visual C++ 10 и более ранних версий, ссылка с [oleaut32.lib].
Я проверил это с помощью MinGW g++ и Visual C++.
PS: В качестве альтернативы вы можете просто istringstream
, но он не дает достоверной информации о том, почему произошел сбой, когда произошел сбой, и, по-видимому, необходимо обнаруживать переполнение как таковое.
Так что "длинный длинный"? Подписанный int64_ может содержать от –9,223,372,036,854,775,808 до 9,223,372,036,854,775,807, и вы можете просто увидеть это из строки. Например, с помощью std:: string:
int stringLength;
string myString("123456789");
stringLength = myString.length();
Этот код получает длину вашей строки. Чтобы определить, переполнен ли он, просто проверьте количество цифр, и, если это может быть переполнение, проверьте первую цифру. Чтобы преобразовать в int64_, используйте приведение:
http://www.learncpp.com/cpp-tutorial/44-type-conversion-and-casting/
Эта ссылка должна ответить на ваш вопрос. (Однако это для строк в стиле C). И последнее уточнение, является ли ваша строка std:: string или нет?