Преобразование строки в 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;
}