Click to See Complete Forum and Search --> : Converting char to a string of hex bytes


motorollin
June 2nd, 2008, 01:21 PM
I might have got some of the terminology wrong here ;) I am very new to C++, and find the data types very confusing.

My app receives data from a socket using recv(), and the data ends up in char "line". I would like to convert "line" to a string of hex values (as strings, not as actual hex bytes) corresponding to the characters within it. I have spent most of the day Googling this and trying every way I can think of, and this is the best I can come up with. Assume that in the data received, line[1] is 0x00, line[2] is 0xBB, line[3] is 0x80 and line[4] is 0x8B.


ostringstream oss;
oss << hex << static_cast<int>( line[1] ) << static_cast<int>( line[2] ) << static_cast<int>( line[3] ) << static_cast<int>( line[4] );
string s = oss.str();


This works, but the output is ugly - something like "0ffffffbbffffff80ffffff8b". I would like the result to be something like "00BB808B".

Hope this makes sense! :)

DreamShore
June 2nd, 2008, 01:46 PM
Casting line[x] to unsigned char would do.

motorollin
June 2nd, 2008, 02:27 PM
Like this?


unsigned char digit;
digit = static_cast<unsigned char>(line[0]);


This compiles, but doesn't seem to do what I want. I want the result to be something like a char* containing the value "21". This seems to be a digit, which outputs the number 33 (the decimal equivalent of 0x21).

Lindley
June 2nd, 2008, 02:29 PM
I don't know where you got the idea another variable needed to be added....he simply meant replacing every instance of static_cast<int>( line[1] ) etc in your above code by static_cast<unsigned char>( line[1] ).

motorollin
June 2nd, 2008, 02:46 PM
Well, ok:


for (int i=0; i<6; i+=1){
line[i]=static_cast<unsigned char>(line[i]);
}


I still can't really see if that has done what I want, since if I printf(buf) it prints the characters themselves, rather than the values I want.

Perhaps I was unclear: I *don't* want them to be chars. I want them to be a single string of the hex codes. So if the data received were represented by the hex values 0xA1, 0xA2, 0xA3, 0xA4, then I would want the end result to be "A1A2A3A4".

motorollin
June 2nd, 2008, 02:57 PM
Ok, the Gods of Google have smiled upon me and I have typed in the precise combination of keywords needed to find this example:


char *StrToHexStr(char *str)
{
char *newstr = new char[(strlen(str)*2)+1];
char *cpold = str;
char *cpnew = newstr;

while('\0' != *cpold) {
sprintf(cpnew, "%02X", (char)(*cpold++));
cpnew+=2;
}
*(cpnew) = '\0';
return(newstr);
}

int main()
{
char * test = StrToHexStr("!@£$%");
printf(test);

return 0;
}


This returns "2140FFFF2425", in which each pair of characters represents the hex value for each of the characters passed to StrToHexStr. This is exactly what I want.

If I pass "line" to it then it only does the first character. If I pass line[i] to it, then it complains because StrToHexStr wants a char* not a char. So I'm guessing I need to iterate through line, do a type conversion of each char to a char*, pass it to StrToHexStr, and append each one to one long string. Or convert the char array to a char* first and then send it to StrToHexStr. More Googling :)

DreamShore
June 2nd, 2008, 03:14 PM
oss << hex << static_cast<int>( (unsigned char)line[1] ) << static_cast<int>( (unsigned char)line[2] )

That's what I meant @_@...

char is signed, so it is sign-extended. And when value beyond 0x7F are expand to larger types 1s are added before it, which make a char value 0x80 becomes 0xFFFFFF80 (both -128) when converted to int value.

VladimirF
June 2nd, 2008, 04:09 PM
oss << hex << static_cast<int>( (unsigned char)line[1] ) << static_cast<int>( (unsigned char)line[2] )

That's what I meant @_@...This will not look very nice for values less than 0x10... You may want to set fixed width and a filler.

Lindley
June 2nd, 2008, 04:09 PM
Be aware that you need to have:
int main()
{
char * test = StrToHexStr("!@£$%");
printf(test);
delete test;

return 0;
}

in order to avoid a memory leak from that code. If you adjusted it to return a std::string instead this would not be a concern.

JohnW@Wessex
June 3rd, 2008, 03:31 AM
If I were doing it I'd do something like this.
#include <string>
#include <iomanip>
#include <sstream>
#include <iostream>

using namespace std;

string StrToHexStr(const string &str)
{
ostringstream text;
string::const_iterator itr = str.begin();

while (itr != str.end())
{
text << hex << setfill('0') << setw(2) << static_cast<int>(static_cast<unsigned char>(*itr));
++itr;
}

return text.str();
}

int main()
{
string test = StrToHexStr("!@£$%");

cout << test;

return 0;
}

BTW 2140FFFF2425 doesn't look correct.
I think it should be 2140A32425.

souldog
June 3rd, 2008, 03:34 AM
John

in the your code above, if you add std::showbase, then

0 is output as 00 instead of 0x00.

Does anyone know how to change this?

JohnW@Wessex
June 3rd, 2008, 03:53 AM
0 is output as 00 instead of 0x00.What string are you inputting?
"0" comes out as "30"

souldog
June 3rd, 2008, 04:01 AM
sorry, I was not clear. I did not mean your code

I have not looked at what I am asking about for about a year, but I seem to remember
that I was trying to display BYTES as hex using manipulators with showbase as well
I could not get the BYTE value 0 to show the base.

I was annoyed by it.

JohnW@Wessex
June 3rd, 2008, 04:05 AM
You also may want to add
<< uppercase
to StrToHexStr if you want all uppercase hex.

JohnW@Wessex
June 3rd, 2008, 04:19 AM
I was annoyed by it.I've just tried a few experiments. Adding showbase seems to screw up the formatting.
Using showbase, hex, setfill('0') & setw(2) as manipulators, value 0 comes out as 00, 1 to 15 as 0x1 to 0xf, completely ignoring the setw(2) directive!

souldog
June 3rd, 2008, 05:02 AM
yah, annoying. I guess one can just do this


std::basic_string<TCHAR> BYTE_TO_TSTRING(const BYTE t)
{
std::basic_ostringstream<_TCHAR, std::char_traits<_TCHAR> > oss;
oss << "0x" << std::hex << std::setw(2) << std::setfill(_T('0')) << static_cast<unsigned int>(t);
return oss.str();
};