views:

13017

answers:

5

I want to convert a hex string to a 32 bit signed integer in C++.

So, for example, I have the hex string "fffefffe". The binary representation of this is 11111111111111101111111111111110. The signed integer representation of this is: -65538.

How do I do this conversion in C++? This also needs to work for non-negative numbers. For example, the hex string "0000000A", which is 00000000000000000000000000001010 in binary, and 10 in decimal.

+10  A: 

use std::stringstream

unsigned int x;   
std::stringstream ss;
ss << std::hex << "fffefffe";
ss >> x;

the following example produces -65538 as its result:

#include <sstream>
#include <iostream>

int main() {
    unsigned int x;   
    std::stringstream ss;
    ss << std::hex << "fffefffe";
    ss >> x;
    // output it as a signed type
    std::cout << static_cast<int>(x) << std::endl;
}

EDIT: It appears that since lexical_cast<> is defined to have stream conversion semantics. Sadly, streams don't understand the "0x" notation. So both the boost::lexical_cast and my hand rolled one don't deal well with hex strings. The above solution which manually sets the input stream to hex will handle it just fine.

Boost has some stuff to do this as well, which has some nice error checking capabilities as well. You can use it like this:

try {
    unsigned int x = lexical_cast<int>("0x0badc0de");
} catch(bad_lexical_cast &) {
    // whatever you want to do...
}

If you don't feel like using boost, here's a light version of lexical cast which does no error checking:

template<typename T2, typename T1>
inline T2 lexical_cast(const T1 &in) {
    T2 out;
    std::stringstream ss;
    ss << in;
    ss >> out;
    return out;
}

which you can use like this:

// though this needs the 0x prefix so it knows it is hex
unsigned int x = lexical_cast<unsigned int>("0xdeadbeef");
Evan Teran
When I use that method, I end up with an integer value of 152144602
Clayton
Remove unsigned, and it should work as advertised.
jmanning2k
@jmanning2k, yea, it's weird that both boost and my lexical_cast barf on hex strings (even with the 0x prefix) if i don't put std::hex in the string.
Evan Teran
For the stringstream example, wouldn't it be appropriate to check the streams failbit and/or badbit?
Torleif
+4  A: 

For a method that works with both C and C++, you might want to consider using the standard library function strtol().

#include <cstdlib>
#include <iostream>
using namespace std;

int main() {
    string s = "abcd";
    char * p;
    long n = strtol( s.c_str(), & p, 16 );
    if ( * p != 0 ) {
     cout << "not a number" << endl;
    }
    else {
     cout << n << endl;
    }
}
anon
I don't often equire the reason for downvotes, but in this case I will - what's wrong with the above code?
anon
I see nothing wrong with this code either. +1 to bring balance to world :-P.
Evan Teran
You should use `strtoul` not `strtol`. There will be `+ overflow` when using strtol. With `strtoul` there will be no overflow and returned value will be converted to `long` to produce correct result (-65538). So your answer almost right :)
Kirill V. Lyadvinsky
+1. Because strtol (or strtoul) faster than using stringstream.
Kirill V. Lyadvinsky
I'd be interested if you expanded on your remarks on overflow (something I always have a problem understanding), possibly in a separate answer?
anon
I've posted answer with detailed explanation.
Kirill V. Lyadvinsky
+5  A: 
Kirill V. Lyadvinsky
+2  A: 

I had the same problem today, here's how I solved it so I could keep lexical_cast<>

typedef unsigned int    uint32;
typedef signed int      int32;

class uint32_from_hex   // For use with boost::lexical_cast
{
    uint32 value;
public:
    operator uint32() const { return value; }
    friend std::istream& operator>>( std::istream& in, uint32_from_hex& outValue )
    {
        in >> std::hex >> outvalue.value;
    }
};

class int32_from_hex   // For use with boost::lexical_cast
{
    uint32 value;
public:
    operator int32() const { return static_cast<int32>( value ); }
    friend std::istream& operator>>( std::istream& in, int32_from_hex& outValue )
    {
        in >> std::hex >> outvalue.value;
    }
};

uint32 material0 = lexical_cast<uint32_from_hex>( "0x4ad" );
uint32 material1 = lexical_cast<uint32_from_hex>( "4ad" );
uint32 material2 = lexical_cast<uint32>( "1197" );

int32 materialX = lexical_cast<int32_from_hex>( "0xfffefffe" );
int32 materialY = lexical_cast<int32_from_hex>( "fffefffe" );
// etc...

(Found this page when I was looking for a less sucky way :-)

Cheers, A.

Andy J Buchanan
+3  A: 

Andy Buchanan, as far as sticking to C++ goes, I liked yours, but I have a few mods:

template <typename ElemT>
struct HexTo {
    ElemT value;
    operator ElemT() const {return value;}
    friend std::istream& operator>>(std::istream& in, HexTo& out) {
        in >> std::hex >> out.value;
        return in;
    }
};

Used like

uint32_t value = boost::lexical_cast<HexTo<uint32_t> >("0x2a");

That way you don't need one impl per int type.

Mike Lundy
I would have taken that step too, but I find that I like to limit the proliferation of angle brackets. For this case I felt breaking the "don't duplicate code" rule was justified. :-)
Andy J Buchanan