9

I am looking for a fastest way to convert a byte array of arbitrary length to a hexadecimal string. This question has been fully answered here at StackOverflow for C#. Some solutions in C++ can be found here.

Are there any "turnkey" or "ready-made" solutions to a problem? C-style solutions are welcome.

Community
  • 1
  • 1
ezpresso
  • 7,896
  • 13
  • 62
  • 94
  • You need to provide more detials of environment etc. to decide on 'fastest' way of implementing this very simple requirement. Is the output string already allocated? How much memory do you have available for lookup tables? 'Arbitrary length' is difficult - with very large arrays, it may be possible to run two or more conversions in parallel. Is your requirement so strict that you cannot just use one of the solutions you linked to? – Martin James Mar 27 '12 at 16:30

4 Answers4

19
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
#include <sstream>
#include <iomanip>

int main() 
{
  std::vector<unsigned char> v;

  v.push_back( 1 );
  v.push_back( 2 );
  v.push_back( 3 );
  v.push_back( 4 );

  std::ostringstream ss;

  ss << std::hex << std::uppercase << std::setfill( '0' );
  std::for_each( v.cbegin(), v.cend(), [&]( int c ) { ss << std::setw( 2 ) << c; } );

  std::string result = ss.str();

  std::cout << result << std::endl;
  return 0;
}

Or, if you've got a compiler that supports uniform initialization syntax and range based for loops you can save a few lines.

#include <vector>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>

int main()
{
  std::vector<unsigned char> v { 1, 2, 3, 4 };
  std::ostringstream ss;

  ss << std::hex << std::uppercase << std::setfill( '0' );
  for( int c : v ) {
    ss << std::setw( 2 ) << c;
  }

  std::string result = ss.str();
  std::cout << result << std::endl;
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
7

Use boost::alogorithm::hex

std::vector<unsigned char> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::string res;
boost::algorithm::hex(v.begin(), v.end(), back_inserter(res));
Like
  • 1,470
  • 15
  • 21
2

You can use the C++ Standard Library and or you can use boost::lexical_cast

#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <sstream>
#include <iomanip>
#include <algorithm>

using namespace std;

// use this macro for c++11 feature
#define USE_CPP11

int main(int argc, char* argv[])
{
    array<unsigned char, 3> hexArr = {0x01, 0xff, 0x55};
    const char separator = ' ';             // separator between two numbers
    ostringstream os;
    os << hex << setfill('0');  // set the stream to hex with 0 fill

#ifdef USE_CPP11
    std::for_each(std::begin(hexArr), std::end(hexArr), [&os, &separator] (int i)
    {
        os << setw(2) << i << separator;
    });
#else       // c++03
    typedef array<unsigned char, 3>::const_iterator const_iterator;
    for (const_iterator it = hexArr.begin(); it != hexArr.end(); ++it)
    {
        os << setw(2) << int(*it) << separator;
    }
#endif
    os << dec << setfill(' ');          // reset the stream to "original"

    // print the string
    cout << "the string array is: " << os.str() << endl;

    return EXIT_SUCCESS;
}
Elvis Dukaj
  • 7,142
  • 12
  • 43
  • 85
1

One of the fastest way I know in C++ 11:

template <size_t byteCount>
string BytesArrayToHexString( const std::array<byte, byteCount>& src )
{
  static const char table[] = "0123456789ABCDEF";
  std::array<char, 2 * byteCount + 1> dst;
  const byte* srcPtr = &src[0];
  char* dstPtr = &dst[0];

  for (auto count = byteCount; count > 0; --count)
  {
      unsigned char c = *srcPtr++;
      *dstPtr++ = table[c >> 4];
      *dstPtr++ = table[c & 0x0f];
  }
  *dstPtr = 0;
  return &dst[0];
}

A good compiler should not have any problem to apply SSE optimization on this....