[Solved] Integer to hex string in C++

How do I convert an integer to a hex string in C++?

I can find some ways to do it, but they mostly seem targeted towards C. It doesn’t seem there’s a native way to do it in C++. It is a pretty simple problem though; I’ve got an int which I’d like to convert to a hex string for later printing.

Solution #1:

Use <iomanip>‘s std::hex. If you print, just send it to std::cout, if not, then use std::stringstream

std::stringstream stream;
stream << std::hex << your_int;
std::string result( stream.str() );

You can prepend the first << with << "0x" or whatever you like if you wish.

Other manips of interest are std::oct (octal) and std::dec (back to decimal).

One problem you may encounter is the fact that this produces the exact amount of digits needed to represent it. You may use setfill and setw this to circumvent the problem:

stream << std::setfill ('0') << std::setw(sizeof(your_type)*2) 
       << std::hex << your_int;

So finally, I’d suggest such a function:

template< typename T >
std::string int_to_hex( T i )
  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;
  return stream.str();

Solution #2:

To make it lighter and faster I suggest to use direct filling of a string.

template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
    static const char* digits = "0123456789ABCDEF";
    std::string rc(hex_len,'0');
    for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
        rc[i] = digits[(w>>j) & 0x0f];
    return rc;

Solution #3:

Use std::stringstream to convert integers into strings and its special manipulators to set the base. For example like that:

std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();
Respondent: phlipsy

Solution #4:

Just print it as an hexadecimal number:

int i = /* ... */;
std::cout << std::hex << i;
Respondent: Etienne de Martel

Solution #5:

You can try the following. It’s working…

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

template <class T>
string to_string(T t, ios_base & (*f)(ios_base&))
  ostringstream oss;
  oss << f << t;
  return oss.str();

int main ()
  cout<<to_string<long>(123456, hex)<<endl;
  return 0;
Respondent: Mahmut EFE

Solution #6:

This question is old, but I’m surprised why no one mentioned boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2
Respondent: s4eed

Solution #7:

int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
Respondent: Mahesh

Solution #8:

Thanks to Lincoln’s comment below, I’ve changed this answer.

The following answer properly handles 8-bit ints at compile time. It doees, however, require C++17. If you don’t have C++17, you’ll have to do something else (e.g. provide overloads of this function, one for uint8_t and one for int8_t, or use something besides “if constexpr”, maybe enable_if).

template< typename T >
std::string int_to_hex( T i )
    // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
    static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

    std::stringstream stream;
    stream << "0x" << std::setfill ('0') << std::setw(sizeof(T)*2) << std::hex;

    // If T is an 8-bit integer type (e.g. uint8_t or int8_t) it will be 
    // treated as an ASCII code, giving the wrong result. So we use C++17's
    // "if constexpr" to have the compiler decides at compile-time if it's 
    // converting an 8-bit int or not.
    if constexpr (std::is_same_v<std::uint8_t, T>)
        // Unsigned 8-bit unsigned int type. Cast to int (thanks Lincoln) to 
        // avoid ASCII code interpretation of the int. The number of hex digits 
        // in the  returned string will still be two, which is correct for 8 bits, 
        // because of the 'sizeof(T)' above.
        stream << static_cast<int>(i);
    else if (std::is_same_v<std::int8_t, T>)
        // For 8-bit signed int, same as above, except we must first cast to unsigned 
        // int, because values above 127d (0x7f) in the int will cause further issues.
        // if we cast directly to int.
        stream << static_cast<int>(static_cast<uint8_t>(i));
        // No cast needed for ints wider than 8 bits.
        stream << i;

    return stream.str();

Original answer that doesn’t handle 8-bit ints correctly as I thought it did:

Kornel Kisielewicz’s answer is great. But a slight addition helps catch cases where you’re calling this function with template arguments that don’t make sense (e.g. float) or that would result in messy compiler errors (e.g. user-defined type).

template< typename T >
std::string int_to_hex( T i )
  // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
  static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;

         // Optional: replace above line with this to handle 8-bit integers.
         // << std::hex << std::to_string(i);

  return stream.str();

I’ve edited this to add a call to std::to_string because 8-bit integer types (e.g. std::uint8_t values passed) to std::stringstream are treated as char, which doesn’t give you the result you want. Passing such integers to std::to_string handles them correctly and doesn’t hurt things when using other, larger integer types. Of course you may possibly suffer a slight performance hit in these cases since the std::to_string call is unnecessary.

Note: I would have just added this in a comment to the original answer, but I don’t have the rep to comment.

Respondent: Loss Mentality

Solution #9:

I do:

int hex = 10;      
std::string hexstring = stringFormat("%X", hex);  

Take a look at SO answer from iFreilicht and the required template header-file from here GIST!

Respondent: CarpeDiemKopi

Solution #10:

My solution. Only integral types are allowed.

Update. You can set optional prefix 0x in second parameter.


#include  <iomanip>
#include <sstream>

template <class T, class T2 = typename std::enable_if<std::is_integral<T>::value>::type>
static std::string ToHex(const T & data, bool addPrefix = true);

template<class T, class>
inline std::string Convert::ToHex(const T & data, bool addPrefix)
    std::stringstream sstream;
    sstream << std::hex;
    std::string ret;
    if (typeid(T) == typeid(char) || typeid(T) == typeid(unsigned char) || sizeof(T)==1)
        sstream << static_cast<int>(data);
        ret = sstream.str();
        if (ret.length() > 2)
            ret = ret.substr(ret.length() - 2, 2);
        sstream << data;
        ret = sstream.str();
    return (addPrefix ? u8"0x" : u8"") + ret;


#include <definition.h>
int main()
    std::cout << ToHex<unsigned char>(254) << std::endl;
    std::cout << ToHex<char>(-2) << std::endl;
    std::cout << ToHex<int>(-2) << std::endl;
    std::cout << ToHex<long long>(-2) << std::endl;

    std::cout<< std::endl;
    std::cout << ToHex<unsigned char>(254, false) << std::endl;
    std::cout << ToHex<char>(-2, false) << std::endl;
    std::cout << ToHex<int>(-2, false) << std::endl;
    std::cout << ToHex<long long>(-2, false) << std::endl;
    return 0;



Respondent: Joma

Solution #11:

For those of you who figured out that many/most of the ios::fmtflags don’t work with std::stringstream yet like the template idea that Kornel posted way back when, the following works and is relatively clean:

#include <iomanip>
#include <sstream>

template< typename T >
std::string hexify(T i)
    std::stringbuf buf;
    std::ostream os(&buf);

    os << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2)
       << std::hex << i;

    return buf.str().c_str();

int someNumber = 314159265;
std::string hexified = hexify< int >(someNumber);
Respondent: Kevin

Solution #12:

Just have a look on my solution,[1] that I verbatim copied from my project, so there a German is API doc included. My goal was to combine flexibility and safety within my actual needs:[2]

  • no 0x prefix added: caller may decide
  • automatic width deduction: less typing
  • explicit width control: widening for formatting, (lossless) shrinking to save space
  • capable for dealing with long long
  • restricted to integral types: avoid surprises by silent conversions
  • ease of understanding
  • no hard-coded limit
#include <string>
#include <sstream>
#include <iomanip>

/// Vertextet einen Ganzzahlwert val im Hexadezimalformat.
/// Auf die Minimal-Breite width wird mit führenden Nullen aufgefüllt;
/// falls nicht angegeben, wird diese Breite aus dem Typ des Arguments
/// abgeleitet. Funktion geeignet von char bis long long.
/// Zeiger, Fließkommazahlen u.ä. werden nicht unterstützt, ihre
/// Übergabe führt zu einem (beabsichtigten!) Compilerfehler.
/// Grundlagen aus:
template <typename T>
inline std::string int_to_hex(T val, size_t width=sizeof(T)*2)
    std::stringstream ss;
    ss << std::setfill('0') << std::setw(width) << std::hex << (val|0);
    return ss.str();

[1] based on the answer by Kornel Kisielewicz
[2] Translated into the language of CppTest, this is how it reads:

TEST_ASSERT(int_to_hex(char(0x12)) == "12");
TEST_ASSERT(int_to_hex(short(0x1234)) == "1234");
TEST_ASSERT(int_to_hex(long(0x12345678)) == "12345678");
TEST_ASSERT(int_to_hex((long long)(0x123456789abcdef0)) == "123456789abcdef0");
TEST_ASSERT(int_to_hex(0x123, 1) == "123");
TEST_ASSERT(int_to_hex(0x123, 8) == "00000123");
// with deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012"); 
Respondent: Wolf

Solution #13:

Code for your reference:

#include <iomanip>
#include <sstream>
string intToHexString(int intValue) {

    string hexStr;

    /// integer value to hex-string
    std::stringstream sstream;
    sstream << "0x"
            << std::setfill ('0') << std::setw(2)
    << std::hex << (int)intValue;

    hexStr= sstream.str();
    sstream.clear();    //clears out the stream-string

    return hexStr;
Respondent: parasrish

Solution #14:

I would like to add an answer to enjoy the beauty of C ++ language. Its adaptability to work at high and low levels. Happy programming.

public:template <class T,class U> U* Int2Hex(T lnumber, U* buffer)
    const char* ref = "0123456789ABCDEF";
    T hNibbles = (lnumber >> 4);

    unsigned char* b_lNibbles = (unsigned char*)&lnumber;
    unsigned char* b_hNibbles = (unsigned char*)&hNibbles;

    U* pointer = buffer + (sizeof(lnumber) << 1);

    *pointer = 0;
    do {
        *--pointer = ref[(*b_lNibbles++) & 0xF];
        *--pointer = ref[(*b_hNibbles++) & 0xF];
    } while (pointer > buffer);

    return buffer;


char buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns "0000000012345678"
Int2Hex(305419896UL, buffer);//returns "12345678"
Int2Hex((short)65533, buffer);//returns "FFFD"
Int2Hex((char)18, buffer);//returns "12"

wchar_t buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns L"0000000012345678"
Int2Hex(305419896UL, buffer);//returns L"12345678"
Int2Hex((short)65533, buffer);//returns L"FFFD"
Int2Hex((char)18, buffer);//returns L"12"
Respondent: ORParga ORParga

Solution #15:

for fixed number of digits, for instance 2:

    static const char* digits = "0123456789ABCDEF";//dec 2 hex digits positional map
    char value_hex[3];//2 digits + terminator
    value_hex[0] = digits[(int_value >> 4) & 0x0F]; //move of 4 bit, that is an HEX digit, and take 4 lower. for higher digits use multiple of 4
    value_hex[1] = digits[int_value & 0x0F]; //no need to move the lower digit
    value_hex[2] = ''; //terminator

you can also write a for cycle variant to handle variable digits amount


  • speed: it is a minimal bit operation, without external function calls
  • memory: it use local string, no allocation out of function stack frame, no free of memory needed. Anyway if needed you can use a field or a global to make the value_ex to persists out of the stack frame
Respondent: Luca C.

Solution #16:

#include <iostream> 
#include <sstream>  

int main()
unsigned int i = 4967295; // random number
std::string str1, str2;
unsigned int u1, u2;

std::stringstream ss;

Using void pointer:

// INT to HEX
ss << (void*)i;       // <- FULL hex address using void pointer
ss >> str1;          //     giving address value of one given in decimals.
ss.clear();         // <- Clear bits
// HEX to INT
ss << std::hex << str1;   // <- Capitals doesn't matter so no need to do extra here
ss >> u1;

Adding 0x:

// INT to HEX with 0x
ss << "0x" << (void*)i;   // <- Same as above but adding 0x to beginning
ss >> str2;
// HEX to INT with 0x
ss << std::hex << str2;   // <- 0x is also understood so need to do extra here
ss >> u2;


std::cout << str1 << std::endl; // 004BCB7F
std::cout << u1 << std::endl;   // 4967295
std::cout << std::endl;
std::cout << str2 << std::endl; // 0x004BCB7F
std::cout << u2 << std::endl;   // 4967295

return 0;
Respondent: Olli V

Solution #17:

int var = 20;
cout <<                          &var << endl;
cout <<                     (int)&var << endl;
cout << std::hex << "0x" << (int)&var << endl << std::dec; // output in hex, reset back to dec

0x69fec4 (address)
6946500 (address to dec)
0x69fec4 (address to dec, output in hex)

instinctively went with this…
int address = (int)&var;

saw this elsewhere…
unsigned long address = reinterpret_cast(&var);

comment told me this is correct…
int address = (int)&var;

speaking of well covered
lightness, where are you at? they’re getting too many likes!

Respondent: Puddle

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Most Popular

To Top
India and Pakistan’s steroid-soaked rhetoric over Kashmir will come back to haunt them both clenbuterol australia bossier man pleads guilty for leadership role in anabolic steriod distribution conspiracy