8

What's the safest and best way to retrieve an unsigned long from a string in C++?

I know of a number of possible methods.

First, converting a signed long taken from atol.

char *myStr; // Initalized to some value somehow.
unsigned long n = ((unsigned)atol(myStr));

The obvious problem with this is, what happens when the value stored in myStr is larger than a signed long can contain? What does atol retrieve?

The next possibility is to use strtoul.

char *myStr; // Initalized to some value somehow.
unsigned long n = strtoul(myStr, 0, 10);

However, this is a little over complicated for my needs. I'd like a simple function, string in, unsigned long base 10 out. Also, the error handling leaves much to be desired.

The final possibility I have found is to use sscanf.

char *myStr; // Initalized to some value somehow.
unsigned long n = 0;
if(sscanf(myStr, "%lu", n) != 1) {
    //do some error handling
}

Again, error handling leaves much to be desired, and a little more complicated than I'd like.

The remaining obvious option is to write my own either a wrapper around one of the previous possibilities or some thing which cycles through the string and manually converts each digit until it reaches ULONG_MAX.

My question is, what are the other options that my google-fu has failed to find? Any thing in the C++ std library that will cleanly convert a string to an unsigned long and throw exceptions on failure?

My apologies if this is a dupe, but I couldn't find any questions that exactly matched mine.

Daniel Bingham
  • 12,414
  • 18
  • 67
  • 93
  • `atol`: "If the correct value is out of the range of representable values, LONG_MAX or LONG_MIN is returned." http://www.cplusplus.com/reference/clibrary/cstdlib/atol/ – Mark Rushakoff Sep 27 '09 at 18:40
  • Couple questions, I'm not sure if they are duplicates though: (1) http://stackoverflow.com/questions/1243428/convert-string-to-int-with-bool-fail-in-c/1243435 (2) http://stackoverflow.com/questions/1435253/c-syntax-question-if-var-type-int/1435268 – GManNickG Sep 27 '09 at 18:41
  • 3
    I don't understand what you have against strtoul. It is the perfect function for this. Pass a 0 for base and it will convert numbers with any base prefix strings your C library understands, like "0x". – Zan Lynx Sep 27 '09 at 20:40

7 Answers7

6

You can use strtoul with no problem. The function returns an unsigned long. If convertion can not be performed the function return 0. If the correct long value is out of range the function return ULONG_MAX and the errno global variable is set to ERANGE.

Patrice Bernassola
  • 14,136
  • 6
  • 46
  • 59
5

One way to do it:

stringstream(str) >> ulongVariable;
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • I editted the question to make more clear that I'm working with C-style strings in this case. So this would have to be streamstream(string(myStr)) >> ulongvariable. Which feels wasteful an inefficient to me :/ I'd rather it were something cleaner and more straight forward. – Daniel Bingham Sep 27 '09 at 18:47
  • 1
    Actually, that is not necessary because `std::string` has a implicit constructor that takes a C-style string as a parameter. That constructor allows you to write just `stringstream("whatever")`. – hrnt Sep 27 '09 at 19:03
  • *smack self* Of course. Even so, it has the result of instantiating two classes - and all the memory management inherent in that - to do what a simple function with a single internal loop ought to be able accomplish. I wish there were something like that built in the standard library. – Daniel Bingham Sep 27 '09 at 19:15
  • Good C++ compilers are aggressive optimizers. Always keep that in mind. I'm not saying it's the fastest way but it should be reasonably fast. – Mehrdad Afshari Sep 27 '09 at 19:24
  • 1
    @Alcon, don't think about the performance until you have to. Are you sure that this code needs to be extremely fast? Are you sure that this solution isn't extremely fast? – tster Sep 27 '09 at 19:41
  • how do I get unsigned long long from char *? – RedFox Sep 22 '16 at 19:16
4
template <class T>
T strToNum(const std::string &inputString,
           std::ios_base &(*f)(std::ios_base&) = std::dec)
{
    T t;
    std::istringstream stringStream(inputString);

    if ((stringStream >> f >> t).fail())
    {
        throw runtime_error("Invalid conversion");
    }
    return t;
}


// Example usage
unsigned long ulongValue = strToNum<unsigned long>(strValue);
int intValue             = strToNum<int>(strValue);

int intValueFromHex      = strToNum<int>(strHexValue,std::hex);
unsigned long ulOctValue = strToNum<unsigned long>(strOctVal, std::oct);
RC.
  • 27,409
  • 9
  • 73
  • 93
2

If you can use the boost libraries (www.boost.org) look at the conversion library - it's a header only include

#include "boost/lexical_cast.hpp"

then all you need to do is

unsigned long ul = boost::lexical_cast<unsigned long>(str);
Bastien Léonard
  • 60,478
  • 20
  • 78
  • 95
  • I'll look into the boost libraries, I was considering using the python interpreting library so using boost might work well for my needs. It'd be nice if there was a simple clean function for this though, for those who don't want a dependency on the boost libraries. – Daniel Bingham Sep 27 '09 at 19:04
1

Jeffrey Stedfast has a beautiful post about writing int parser routines for Mono (in C).
It generates code that uses uses native types (you need 32 bit to parse 32 bit) and error codes for overflow.

Shay Erlichmen
  • 31,691
  • 7
  • 68
  • 87
1

Use "atol" in-built std function

For example std::string input = "1024";

std::atol(input.c_str());

Atol expect parameter to be of type c string, so c_str() does it that for you.

PURVESH PATEL
  • 199
  • 2
  • 8
0

Robust way will be write a static function and use it

bool str2Ulong(const string& str,unsigned long & arValue)
{
   char *tempptr=NULL;
   arValue=strtoul(str,tempptr,10);

   return ! (arValue==0 && tempptr==str.c_str());

}
Satbir
  • 6,358
  • 6
  • 37
  • 52