using std::stringstream to print a string in hex decimal form

I am using a log4cpp  to log any debug info to a file.

log4cpp::Category::getRoot() <<  log4cpp::Priority::DEBUG << "My error string";

There is time I would like to turn the error string into an array of hex codes for each character in the string

log4cpp::Category::getRoot() <<  log4cpp::Priority::DEBUG << "0x65 0x63 0x67 0x68 .. .. ..";

What is the best way to transform "My error string" to "0x65 0x63 0x67 0x68 .. .. .."
tommym121Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
sarabandeConnect With a Mentor Commented:
if you want display a string buffer like a hex editor does which shows the hex values in a table at the left side and the printable characters for each row at the right side

     | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 |
-----|-------------------------------------------------|-----------------
0000 | 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 20 0a 49 20 | Hello World! .I
0016 | 61 6d 20 68 65 72 65 2e 20 57 68 65 72 65 20 61 | am here. Where a
0032 | 72 65 20 79 6f 75 3f 0a 00 00 00 00 00 00 00 00 | re you?.

Open in new window


you could advance and improve the functor jkr has shown by

struct hexedit 
{
    std::string        srow;
    int nrows;
    
    std::ostringstream & get_oss()
    {
        static std::ostringstream oss;
        return oss;
    }
    hexedit() : nrows(0)
    {
        get_oss() = std::ostringstream();
        get_oss() << "     | 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 |" << std::endl 
                  << "-----|-------------------------------------------------|-----------------" << std::endl 
                  << "0000 | ";
    }
    ~hexedit()
    {
        if (srow.empty() == false)
        {
            this->operator()('\0', true);
        }
    }
    
    void operator() (char c, bool bend = false) 
    { 
        if (bend == true)
        {
            std::string send = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ";
            send = send.substr(srow.length()*3);
            get_oss() << send << srow << std::endl;
            return;
        }
        if (srow.length() == 16)
        {
            get_oss() << "| " << srow << std::endl << std::dec << std::right << std::setw(4) << std::setfill('0') << (++nrows)*16 << " | "; 
            srow = "";
        }
        get_oss() << std::hex << std::setw(2) << std::right << std::setfill('0') << (int) c << ' '; 
        srow += (isprint(c) == 0)? '.' : c;
    }
};

std::ostream& operator<<(std::ostream& os, hexedit& he)
{   
    os << he.get_oss().str(); 
    return os;
}

int main()
{
    std::string s = "Hello World! \nI am here. Where are you?\n";  
    std::cout <<  std::for_each(s.begin(), s.end(), hexedit()) << std::endl;
    s = "0123456789012345";
    std::cout <<  std::for_each(s.begin(), s.end(), hexedit()) << std::endl;
    return 0;
}

Open in new window


note, the code doesn't use template classes as it is specialized for char type only anyhow. it also doesn't require to pass a stringstream object but uses an own temporary.

Sara
0
 
sarabandeConnect With a Mentor Commented:
you could use std::ostringstream and iomanip:

#include <sstream>
#include <iomanip>

...
std::ostringstream oss;
for (int n = 0; n < (int)input_string; ++n)
{
      oss << "0x" << std::hex << std::right << std::setw(2) << std::setfill('0')
             << (int)input_string[n] << ' ';
}

Open in new window


Sara
0
 
jkrConnect With a Mentor Commented:
'<algorithm>' has a few neat helpers to make that simpler, e.g.

#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <iomanip>
using namespace std;


template<class T> struct hexify {

  hexify(stringstream& out) : ss(out) {}
  void operator() (T& x) { ss << setbase(16) << "0x" << (int) x << ' ';}
  stringstream& ss;
};

template<class T>
ostream& operator<<(ostream& os, const hexify<T>& h) { os << h.ss.str(); return os;}

int main() {

  string s = "My error message";
  stringstream ss;

  cout <<  for_each(s.begin(), s.end(), hexify<char>(ss)) << endl;

  // Or, as in your case:
  //
 // log4cpp::Category::getRoot() <<  log4cpp::Priority::DEBUG << for_each(s.begin(), s.end(), hexify<char>(ss)) << endl;

  return 0;
}

Open in new window

0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
tommym121Author Commented:
JKR,

I really like your new trick, as I am learning to apply generic programming. (template).

One more winkle I like to add, what if I would like to print max16 Hex numbers in a row.

how would I do it.
0
 
jkrConnect With a Mentor Commented:
You mean like adding a line break after 16 characters? E.g like

#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <iomanip>
using namespace std;


template<class T> struct hexify {

  hexify(stringstream& out) : ss(out), count(0) {}
  void operator() (T& x) { ss << setbase(16) << "0x" << (int) x << ' '; if(!((count +1 ) % 16)) ss << endl; ++count;}
  stringstream& ss;
  unsigned int count;
};

template<class T>
ostream& operator<<(ostream& os, const hexify<T>& h) { os << h.ss.str(); return os;}

int main() {

  string s = "My error message My error message My error message My error message";
  stringstream ss;

  cout <<  for_each(s.begin(), s.end(), hexify<char>(ss)) << endl;

  // Or, as in your case:
  //
 // log4cpp::Category::getRoot() <<  log4cpp::Priority::DEBUG << for_each(s.begin(), s.end(), hexify<char>(ss)) << endl;

  return 0;
}                                

Open in new window

0
 
tommym121Author Commented:
JKR,

I forget to mention if what I am trying to print out is an array of char (e.g. TCP/IP) packet, '\n' can be present in the char array, I would like to print '\n' as ASCII code  and still able to print 16 maximum HEX number in a row.  

So I suppose I can not use string or stringstream am I right
0
 
jkrConnect With a Mentor Commented:
The above should take care of it ;o)

Edit: *Will* definitely take care of it:

#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
#include <iomanip>
using namespace std;


template<class T> struct hexify {

  hexify(stringstream& out) : ss(out), count(0) {}
  void operator() (T& x) { ss << setbase(16) << "0x" << (int) x << ' '; if(!((count +1 ) % 16)) ss << endl; ++count;}
  stringstream& ss;
  unsigned int count;
};

template<class T>
ostream& operator<<(ostream& os, const hexify<T>& h) { os << h.ss.str(); return os;}

int main() {

  string s = "My error message\n My error message\n My error message\n My error message";
  stringstream ss;

  cout <<  for_each(s.begin(), s.end(), hexify<char>(ss)) << endl;

  // Or, as in your case:
  //
 // log4cpp::Category::getRoot() <<  log4cpp::Priority::DEBUG << for_each(s.begin(), s.end(), hexify<char>(ss)) << endl;

  return 0;
}

Open in new window

0
 
tommym121Author Commented:
Thanks
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.