169

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.

3

12 Answers 12

283

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

In the new C++11 standard, there are a few new utility functions which you can make use of! specifically, there is a family of "string to number" functions (http://en.cppreference.com/w/cpp/string/basic_string/stol and http://en.cppreference.com/w/cpp/string/basic_string/stoul). These are essentially thin wrappers around C's string to number conversion functions, but know how to deal with a std::string

So, the simplest answer for newer code would probably look like this:

std::string s = "0xfffefffe";
unsigned int x = std::stoul(s, nullptr, 16);

NOTE: Below is my original answer, which as the edit says is not a complete answer. For a functional solution, stick the code above the line :-).

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"); 
Sign up to request clarification or add additional context in comments.

9 Comments

When I use that method, I end up with an integer value of 152144602
@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.
@SteveWilkinson: Read the paragraph starting with the "EDIT". It explains how you need to use std::hex
For stringstreams one should check ss.good() && ss.eof() to make sure no errors occurred.
this "stoul" save my logic
|
73

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 ) { //my bad edit was here
        cout << "not a number" << endl;
    }
    else {
        cout << n << endl;
    }
}

3 Comments

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 :)
+1. Because strtol (or strtoul) faster than using stringstream.
Bug: string s = ""; does not cause "not a number".
27

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.

4 Comments

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. :-)
Unfortunate that it's necessary, but nicely done. Added to my personal STL/Boost extensions/fixes header. Thanks!
Unfortunately this only works for unsigned conversion. So you can not convert 0xFFFFFFFF to -1.
@fmuecke: That's because 0xFFFFFFFF is a signed integer overflow, which is undefined behavior.
16

Working example with strtoul will be:

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

int main() { 
    string s = "fffefffe";
    char * p;
    long n = strtoul( s.c_str(), & p, 16 ); 
    if ( * p != 0 ) {  
        cout << "not a number" << endl;
    }    else {  
        cout << n << endl;
    }
}

strtol converts string to long. On my computer numeric_limits<long>::max() gives 0x7fffffff. Obviously that 0xfffefffe is greater than 0x7fffffff. So strtol returns MAX_LONG instead of wanted value. strtoul converts string to unsigned long that's why no overflow in this case.

Ok, strtol is considering input string not as 32-bit signed integer before convertation. Funny sample with strtol:

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

int main() { 
    string s = "-0x10002";
    char * p;
    long n = strtol( s.c_str(), & p, 16 ); 
    if ( * p != 0 ) {  
        cout << "not a number" << endl;
    }    else {  
        cout << n << endl;
    }
}

The code above prints -65538 in console.

Comments

10

Here's a simple and working method I found elsewhere:

string hexString = "7FF";
int hexNumber;
sscanf(hexString.c_str(), "%x", &hexNumber);

Please note that you might prefer using unsigned long integer/long integer, to receive the value. Another note, the c_str() function just converts the std::string to const char* .

So if you have a const char* ready, just go ahead with using that variable name directly, as shown below [I am also showing the usage of the unsigned long variable for a larger hex number. Do not confuse it with the case of having const char* instead of string]:

const char *hexString = "7FFEA5"; //Just to show the conversion of a bigger hex number
unsigned long hexNumber; //In case your hex number is going to be sufficiently big.
sscanf(hexString, "%x", &hexNumber);

This works just perfectly fine (provided you use appropriate data types per your need).

Comments

8

just use stoi/stol/stoll for example:

std::cout << std::stol("fffefffe", nullptr, 16) << std::endl;

output: 4294901758

2 Comments

Just edit stol to stoi
Bug: when long is 32-bit, this reports output: 2147483647.
7

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.

1 Comment

Code has trivial compilation error - outvalue is not defined (should be outValue).
3

This worked for me:

string string_test = "80123456";
unsigned long x;
signed long val;

std::stringstream ss;
ss << std::hex << string_test;
ss >> x;
// ss >> val;  // if I try this val = 0
val = (signed long)x;  // However, if I cast the unsigned result I get val = 0x80123456 

Comments

3

Try this. This solution is a bit risky. There are no checks. The string must only have hex values and the string length must match the return type size. But no need for extra headers.

char hextob(char ch)
{
    if (ch >= '0' && ch <= '9') return ch - '0';
    if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
    if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
    return 0;
}
template<typename T>
T hextot(char* hex)
{
    T value = 0;
    for (size_t i = 0; i < sizeof(T)*2; ++i)
        value |= hextob(hex[i]) << (8*sizeof(T)-4*(i+1));
    return value;
};

Usage:

int main()
{
    char str[4] = {'f','f','f','f'};
    std::cout << hextot<int16_t>(str)  << "\n";
}

Note: the length of the string must be divisible by 2

1 Comment

std::hex and std::stoul() and sscanf() are permissive, so if I pass a wrong "FK" it would result in 15 (ignores K and considers F). at hextob I changed the return to std::cerr<<"ERROR: invalid ch='"<<ch<<"'"<<"\n";exit(1);, this way I can grant the input was perfect, but I am using this instead, for just at most 0xFF int hexaTo(const char* pch) {return hextob(pch[0])*16+hextob(pch[1]);}
1

For those looking to convert number base for unsigned numbers, it is pretty trivial to do yourself in both C/C++ with minimal dependency (only operator not provided by the language itself is pow() function).

In mathematical terms, a positive ordinal number d in base b with n number of digits can be converted to base 10 using:

math summation

Example: Converting base 16 number 00f looks like:

math summation = 0*16^2 + 0*16^1 + 16*16^0 = 15

C/C++ Example:

#include <math.h>

unsigned int to_base10(char *d_str, int len, int base)
{
    if (len < 1) {
        return 0;
    }
    char d = d_str[0];
    // chars 0-9 = 48-57, chars a-f = 97-102
    int val = (d > 57) ? d - ('a' - 10) : d - '0';
    int result = val * pow(base, (len - 1));
    d_str++; // increment pointer
    return result + to_base10(d_str, len - 1, base);
}

int main(int argc, char const *argv[])
{
    char n[] = "00f"; // base 16 number of len = 3
    printf("%d\n", to_base10(n, 3, 16));
}

2 Comments

to_base10 function accepts any string ( char * ) without checking if the provided string is hex or not
True. Though implementing error handling in C would be interesting since assigning an integer as an error code (e.g., -1) would clash with its valid hex representation of said error code (and exceptions obviously aren't an option in C). I guess one way to try and avoid confusion would be to just rename to hex_to_base10.
0

More simple I think :)

char StringValue[10] = "fe";

int iVal;

sscanf(StringValue,"%x",&iVal);

printf("String : '%s', Val : %d",StringValue, iVal);

Write :

String : 'fe', Val : 254 

1 Comment

Please read the code formatting guide, and make sure to include a description of why this code works in addition to the code itself in an edit.
0

To avoid the overflow from @Evan Teran 's answer, I'll just use a wider type, ie size_t suitable for common use cases.

convert.cpp

#include <iostream>
#include <sstream>
#include <exception>

size_t convertHex(const std::string& hexStr)
{
    std::cout << "This trick can print values up to: " << static_cast<size_t>(-1);
    std::cout << std::endl;

    std::stringstream ssBuff {};
    size_t x {0};

    ssBuff << std::hex << hexStr;
    ssBuff >> x;

    if(!ssBuff.eof() || ssBuff.fail())
    {
        throw std::runtime_error("Conversion in stringstream failed.");
    }

    return x;
}

int main(int argc, char* argv[])
{
    if(2 != argc)
    {
        std::cout << "Usage: " << argv[0] << "  [hex_string_to_convert].";
        std::cout <<  std::endl;
        return -1;
    }

    try
    {
        std::string hexStr{argv[1]};
        size_t value = convertHex(hexStr);
        std::cout << hexStr << " = " << value << std::endl;
    }
    catch(std::runtime_error &e)
    {
        std::cout << "\tError: " << e.what() << std::endl;
        return -1;
    }

    return 0;
}
g++ -o app convert.cpp && ./app fffefffe

Output:

This trick can print values up to: 18446744073709551615

fffefffe = 4294901758

./app fffefffefffffffffffffffffffffffffffffffff

Output:

This trick can print values up to: 18446744073709551615

Error: Conversion in stringstream failed.

3 Comments

"I'll just use a wider type, ie size_t" --> size_t may be as narrow as 16-bit. Consider intmax_t, long long or int64_t for a wide signed type.
@chux All std containers operate on size_t as it is guaranteed to be large enough...
"All std containers operate on size_t as it is guaranteed to be large enough" is true for sizing yet it does not apply to OP's <I have the hex string "fffefffe">. The issue is converting at least a 32-bit value, not some object/array size issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.