Преобразование строки в unsigned int возвращает неверный результат

У меня есть следующая строка:

sThis = "2154910440";

unsigned int iStart=atoi(sThis.c_str());

Однако результат

iStart = 2147483647

Кто-нибудь видит мою ошибку?

Ответы

Ответ 1

atoi преобразует строку в int. В вашей системе int - 32 бита, а его максимальное значение равно 2147483647. Значение, которое вы пытаетесь преобразовать, выходит за пределы этого диапазона, поэтому возвращаемое значение atoi равно undefined. По-моему, ваша реализация возвращает максимальное значение int в этом случае.

Вместо этого вы можете использовать atoll, который возвращает длинный длинный, который гарантированно составляет не менее 64 бит. Или вы можете использовать функцию из семейства stoi/stol/stoll или их неподписанных копий, что фактически даст полезные сообщения об ошибках на значениях вне диапазона (и недопустимые значения) в виде исключений.

Лично мне нравится boost::lexical_cast. Несмотря на то, что он выглядит немного громоздким, его можно использовать в более общем контексте. Вы можете использовать его в шаблонах и просто переслать аргумент типа вместо необходимости иметь специализации

Ответ 2

atoi возвращает подписанный int, который на вашей платформе имеет максимальное значение 2^31-1.

Не имеет значения, к чему вы назначаете этот результат, он будет ограничен типом возвращаемого значения.

Потоки С++ могут читать беззнаковые ints.

std::istringstream reader(sThis);
unsigned int val;
reader >> val;

Ответ 3

Вместо этого вы должны использовать std::strtoul, найденный в <cstdlib>, который предназначен для неподписанных номеров, имеет больший диапазон и лучше сообщает об ошибках.

Если вы хотите использовать std::string для ввода и исключения для обработки ошибок, используйте std::stoul. Краткая, высокоэффективная реализация будет следующей:

#include <string>
#include <stdexcept>
inline unsigned int stoui(const std::string& s)
{
    unsigned long lresult = stoul(s, 0, 10);
    unsigned int result = lresult;
    if (result != lresult) throw std::out_of_range();
    return result;
}

Это будет намного быстрее, чем istringstream, культурно-инвариантный (поэтому никаких неожиданных изменений в поведении при работе в необычной локали), полностью переносимый и использующий третий аргумент, вы можете поддерживать разные числовые базы или даже выполнять обнаружение префиксов 0x и 0.

Но unsigned int не обязательно достаточно велик, чтобы сохранить ваше значение, поэтому используйте unsigned long, и тогда вам не понадобится вышеуказанная оболочка.

Ответ 4

Беззнаковый int часто является 32-битным значением в С++, который имеет максимум 4 294 967 295. Таким образом, 2 154 710 440 может быть представлено как неподписанный int. Тем не менее, atoi преобразуется в int, который подписан и имеет максимальное значение 2 147 483 647 - так что строка переполняет диапазон значений, поэтому ваш ответ неверен. Вы можете использовать atoll, который преобразует вашу строку в длинный длинный, который будет не менее 64 бит. Целочисленные размеры зависят от компилятора на С++. Часто лучше включать заголовочный файл stdint.h, а затем использовать uint32_t или uint64_t и т.д., Чтобы вы знали размер, с которым имеете дело.

Ответ 5

Не забывайте, что вы всегда можете написать свою собственную функцию, которая делает точно то, что вы хотите.

Этот код будет работать с любым числом между -9223372036854775806 (2 ^ 63 + 1) и 9223372036854775807 (2 ^ 63-1) включительно.

Что-то вроде этого:

long long int myAtoi ( string str ) {
    long long int value = 0;

    for (int i = 0; i < str.size(); i++) {

        if (str[i] != '-') {
            value *=  10;
            value += (int) ((str[i]) - '0');
        }
    }


    if (str.size() > 0 && str[0] == '-')
        return -value;
    else
        return value;
}

Ответ 6

вы можете использовать atol, который преобразует строку в long int. Чтобы узнать больше, посмотрите man atol в Linux.

прототип

#include <stdlib.h>
long atol(const char *nptr);

Ответ 7

К сожалению, у С++ нет встроенной реализации для синтаксического анализа unsigned int, и это действительно странно.

Вот код, который может вам помочь:

#include <stdint.h>
#include <sstream>

inline unsigned int stoui(const std::string& s)
{
    std::istringstream reader(s);
    unsigned int val = 0;
    reader >> val;
    return val;
}

// This may be not the same as stoui on some platforms:
inline uint32_t stoui32(const std::string& s)
{
    std::istringstream reader(s);
    uint32_t val = 0;
    reader >> val;
    return val;
}