tmighty
tmighty

Reputation: 11409

Converting string to unsigned int returns the wrong result

I have the following string:

sThis = "2154910440";

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

However the result is

iStart = 2147483647

Does anybody see my mistake?

Upvotes: 24

Views: 103096

Answers (8)

GizMoCuz
GizMoCuz

Reputation: 13

This code will convert it with C++11:

std::string sThis = "2154910440";
unsigned int iStart = static_cast<unsigned int>(std::stoul(sThis));

std::stoul will return an unsigned long, which is larger than an unsigned int.

static_cast will convert it to the right type.

Upvotes: 1

Sergey
Sergey

Reputation: 1590

Unfortunately C++ has no embedded implementation for parsing unsigned int and this is really strange.

Here is a code which can help you:

#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;
}

Upvotes: 1

Ben Voigt
Ben Voigt

Reputation: 283793

You should instead use std::strtoul, found in <cstdlib>, which is designed for unsigned numbers, has a larger range, and reports errors better.

If you want to use std::string for input and exceptions for error handling, use std::stoul. A short, highly efficient implementation would be as follows:

#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;
}

This will be much faster than istringstream, culture-invariant (so no unexpected changes to behavior when run in an unusual locale), completely portable, and using the third argument, you can support different numeric bases or even perform detection of 0x and 0 prefixes.

But unsigned int isn't necessarily big enough to hold your value, so use unsigned long, and then you won't need the above wrapper.

Upvotes: 16

Madan Ram
Madan Ram

Reputation: 876

you can use atol which convert string to long int . To read more see the man atol in Linux.

the prototype

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

Upvotes: 1

Benjamin Lindley
Benjamin Lindley

Reputation: 103741

atoi converts a string to an int. On your system, an int is 32 bits, and its max value is 2147483647. The value you are trying to convert falls outside this range, so the return value of atoi is undefined. Your implementation, I guess, returns the max value of an int in this case.

You could instead use atoll, which returns a long long, which is guaranteed to be at least 64 bits. Or you could use a function from the stoi/stol/stoll family, or their unsigned counterparts, which will actually give useful error reports on out of range values (and invalid values) in the form of exceptions.

Personally, I like boost::lexical_cast. Even though it appears a bit cumbersome, it can be used in a more general context. You can use it in templates and just forward the type argument instead of having to have specializations

Upvotes: 46

Oleksiy
Oleksiy

Reputation: 39859

Don't forget, you can always write your own function that does exactly what you want.

This code will work with any number between -9223372036854775806 (2^63+1) and 9223372036854775807 (2^63-1) inclusive.

Something like this:

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;
}

Upvotes: 2

David Elliman
David Elliman

Reputation: 1399

An unsigned int is often a 32 bit value in C++ which has a maximum of 4,294,967,295. 2,154,710,440 can therefore be represented as an unsigned int. However, atoi converts to an int which is signed and has a maximum value of 2,147,483,647 - so you string overflows the value range whichis why your answer is incorrect. You could use atoll which converts your string to a long long which will be at least 64 bits. Integer sizes are compiler dependent in C++. It is often better to include the header file stdint.h and then use uint32_t or uint64_t and so on, so that you know the size you are dealing with.

Upvotes: 1

helloworld922
helloworld922

Reputation: 10939

atoi returns a signed int, which on your platform has a max value of 2^31-1.

It doesn't matter what you're assigning that result to, it will be bounded by the return type.

C++ streams can read unsigned ints.

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

Upvotes: 11

Related Questions