Определить, будет ли число (закодированное в виде строки) соответствовать 64-разрядному целому числу в C ++? - PullRequest
2 голосов
/ 28 марта 2012

Я ищу портативный способ а) преобразовать строку в 64-разрядное целое число со знаком (int64_t) и б) определить, не подходит ли она (переполнение). Есть ли способ сделать это?

Ответы [ 5 ]

1 голос
/ 28 марта 2012

Пробежитесь по символам строки по одному и сделайте ваше целое число. если анализируемый символ вызовет переполнение, то вы знаете, что собираетесь переполниться. этот код является основной идеей - он не обрабатывает ошибки или отрицательные числа, но должен дать вам идею ...

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 - спасибо за подсказку :))

1 голос
/ 28 марта 2012

strtoll больше переносим. И если не в вашем случае, вы всегда можете написать библиотеку времени выполнения GNU C и добавить ее в свой проект ...

errno = 0;
long long val = strtoll (string, NULL, 0);
if (errno == ERANGE)
   // there was an overflow conversion error
0 голосов
/ 01 февраля 2014

Основываясь на полезном ответе Джошуа Глейзера, я нашел следующее решение, которое выполняет проверку ошибок, а также работает для отрицательных целых чисел:

#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;
}
0 голосов
/ 28 марта 2012

Для обслуживания 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, но он не может точно сказать вам почему произошел сбой при сбое - и, как представляется, необходимо обнаруживать переполнение как таковое.

0 голосов
/ 28 марта 2012

Итак, «длинный длинный»? Подписанный 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 или нет?

...