Saturday, April 18, 2009

Verifying an array is easy with dump program

Sometimes, I need to see or dump data inside the array into screen. It is simple job, and often required in cases when I'm dealing with raw data moving from here to there. Such cases can be transferring data through Internet using TCP/IP socket or using more higher protocol like HTTP or moving data to and from raw file structure or even disk itself. It may be necessary to create well defined monitoring program for such cases. However, in many cases dumping bunch of data inside the array into screen without running into debugger, like GDB, is quite useful.

Here is a simple data dump program that can dump array of simple data type like integer or char into screen. Although it is defined as template, the use of type T in the program is limited to primitive data type like integer, float, or char. Although limiting the usage of T through, for example, specialization is possible, I only focused on what is intended, dumping simple data. Using this template with more sophisticated structure like class is limited to hex dump and non-pointer like members only. As implied before, it does not provide any mechanism to check error arose from wrongful usage of type.

template<typename T>
void dump(T* from, T* to,
const _Ios_Fmtflags fmt=ios_base::hex,
const int width=0,
const int maxline=20,
const char* header = "<======== start dump =========>",
const char* footer = "<========= end dump ==========>") {
_Ios_Fmtflags org = cout.flags();
cout.flags(fmt);
int size = width;
if (!width) {
size = sizeof(T) << 1;
switch(fmt) {
case ios_base::oct:
size <<= 1;
case ios_base::hex:
cout << setfill('0');
break;
default:
if (sizeof(T) == 1) size = 3;
else {
ostringstream str;
str << numeric_limits<T>::max();
size = str.str().length();
}
break;
}
}
cout << header << endl;
int itr = 1;
if (sizeof(T) > 1) {
for(itr = 1; from != to; ++from, ++itr) {
cout << setw(size) << *from << ',';
if (!(itr % maxline))
cout << endl;
}
if ( ((itr - 1) % maxline) )
cout << endl;
} else {
unsigned char* f = (unsigned char*)from;
unsigned char* t = (unsigned char*)to;
for(itr = 1; f != t; ++f, ++itr) {
cout << setw(size) << (short)*f << ',';
if (!(itr % maxline))
cout << endl;
}
if ( ((itr - 1) % maxline) )
cout << endl;
}
cout << footer << endl;
cout.flags(org);
if (fmt == ios_base::hex || fmt == ios_base::oct)
cout << setfill(' ');
}

As you can see from the source code, dump() accepts up to 7 arguments to format the output. First two out of seven are necessary, because they define what to dump. But the rest of arguments can be left as default. Third one in argument, “fmt”, control how to display numbers in screen, and the default value is hexadecimal format, which I prefer. Fourth “width” is for minimum width of each data, and fifth “maxline” is for the number of data in a line. Sixth and seventh argument are header and footer to write, which I used to distinguish from one dump to another.

Usage is simple. For example, if I want to dump an array of characters in buffer into screen, which occurs mostly to me, type like this


char buffer[1024];
...
dump(buffer, buffer+1024);


then the result will be


<======== start dump =========>
0a,00,72,e1,09,00,61,19,04,9e,3f,44,8b,6c,e7,fb,a9,0a,40,00,
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,
...

No comments:

Post a Comment