Click here to Skip to main content
15,878,852 members
Articles / Programming Languages / C++
Tip/Trick

Memory Dump to outstream

Rate me:
Please Sign up or sign in to vote.
4.90/5 (18 votes)
4 Apr 2018BSD1 min read 15.3K   268   16   7
Function and supporting class to write a memory dump with hex values and characters to an output stream

Introduction

This is a simple piece of code which dumps a section of memory - with address, hex values, and characters - to a stream. I've written something like this a lot of times over the years, whenever I've needed a quick memory dump to log during debugging. 

I wanted to make it easy to stream out, so I wrote this as a function which takes a memory address and number of bytes and returns an object with those parameters. This object's class has a function to dump the memory, and a befriended output operator that calls it, so the function can be called in a stream sequence.

Code

Since this is something I'd mostly use while debugging, I keep it all in a single header file, to make it easy to add when needed.

C++
#include <iostream>
#include <iomanip>

//! Class to send a memory dump to stream
class mem_dumper
{
public:
   //! Constructor
    /*! Construct object that can be serialised out to stream
        \param address start address of memory to serialise
        \param length number of bytes to serialise
     */
   mem_dumper(const void* address, size_t length)
   : address_(address), length_(length) 
   {}

private:
   // Address of data to dump
   const void* address_;
   // Number of bytes to dump
   size_t length_;

   // Give streaming operator access to streaming function
   friend std::ostream& operator<<(std::ostream& os, const mem_dumper& md);

   // Streaming function
   std::ostream& dump(std::ostream& os) const
   {
      // Save stream state
      std::ios state(NULL);
      state.copyfmt(os);

      os << std::hex << std::setfill('0');
      size_t index = 0;
      const unsigned char* address = static_cast<const unsigned char*>(address_);
      while (index < length_)
      {
         // Address
         os << std::endl << std::setw(8) << (unsigned long)address_ + index;

         // Up to 16 bytes per line
         size_t width = (length_ - index) > 16 ? 16 : (length_ - index);
         
         // Hex codes
         for (size_t i = 0; i < 16; i++ )
         {
            // Gap after a 0 and 8 characters
            if( i % 8 == 0 )
               os << ' ';

            // Put in filler if we run out of bytes at the end
            if( i < width )
               os << ' ' << std::setw(2) << std::hex << (unsigned short)address[i+index];
            else 
               os << "   ";
         }
         os << ' ';

         // Printable characters
         for( size_t i = 0; i < width; i++)
         {
            if( i % 8 == 0 )
               os << ' ';
            if( address[i+index] < 32 )
               os << '.';
            else 
               os << address[i+index];
         }
         index += 16;
      }
      // Restore state
      os.copyfmt(state);
      return os;
   }
};

//! Stream operator for a mem_dumper
/*! Stream operator for a mem_dumper
    \param os output stream
    \param md mem_dumper object to serialise
    \return output stream
 */
std::ostream& operator<<(std::ostream& os, const mem_dumper& md)
{
    return md.dump(os);
}

//! Create a mem_dumper which can be serialised
/*! Create a mem_dumper which can be serialised
    \param address start address of memory to serialise
    \param length number of bytes to serialise
    \return mem_dumper object
 */
inline mem_dumper mem_dump(const void* address, size_t length)
{
    return mem_dumper(address, length);
}

Using the Code

To use it, simply pass in the address of the data and how many bytes you want to dump into the function, and send it to an output stream:

C++
#include "mem_dump.hpp"

struct ExampleData
{
    char text[22];
    bool b;
    int i;
    ExampleData()
    {
        memcpy(text, "Blabla bla. Blah? Bla!", 22);
        b = true;
        i = 1234567;
    }
} data;

std::cout << mem_dump(&data, sizeof(ExampleData)) << std::endl;

This will produce (address will vary, and the characters representing the int bytes will vary depending on platform codepage):

0022FAC8  42 6c 61 62 6c 61 20 62  6c 61 2e 20 42 6c 61 68  Blabla b la. Blah
0022FAD8  3f 20 42 6c 61 21 01 cc  87 d6 12 00              ? Bla!.╠ çÍ.

History

  • 26th March, 2018: Initial version
  • 28th March, 2018: Fixed address printout increment issue in text and downloadable file

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Software Developer (Senior)
Sweden Sweden
Orjan has worked as a professional developer - in Sweden and England - since 1993, using a range of languages (C++, Pascal, Delphi, C, C#, Visual Basic, Python and assemblers), but tends to return to C++.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Doom For Ever14-Mar-19 11:11
professionalDoom For Ever14-Mar-19 11:11 
Questiondownloaded zip misses some lines Pin
ehaerim30-Mar-18 4:02
ehaerim30-Mar-18 4:02 
AnswerRe: downloaded zip misses some lines Pin
Orjan Westin4-Apr-18 2:15
professionalOrjan Westin4-Apr-18 2:15 
QuestionNice Job Pin
jeffie10029-Mar-18 4:25
jeffie10029-Mar-18 4:25 
QuestionVery clean Pin
John R. Shaw28-Mar-18 6:52
John R. Shaw28-Mar-18 6:52 
QuestionWhy address is not updated in every line? Pin
Shao Voon Wong27-Mar-18 19:37
mvaShao Voon Wong27-Mar-18 19:37 
AnswerRe: Why address is not updated in every line? Pin
Orjan Westin28-Mar-18 1:18
professionalOrjan Westin28-Mar-18 1:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.