• Create Account

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

19 replies to this topic

### #1Psychopathetica  Members

Posted 26 January 2014 - 12:08 AM

This may sound strange but I know how to display hexadecimals in C with the printf() using \x and in C++ using cout << hex << your_int_here, but what if I wanted to store that hexadecimal in a string? And I'm not talking about using the char data type but rather the string data type from the library #include <string>. Is it possible without having to design my own hex to string conversion function?

### #2frob  Moderators

Posted 26 January 2014 - 12:18 AM

POPULAR

There is a built in class that mixes strings with streams. It has the hopefully unsurprising name of stringstream.

You can treat it like a stream, using the stream extraction and stream insertion methods. You can dump the content's with the .str() method.

There are quite a few useful string-based conversions you can do with it, including your example question. There are many lexical-style conversions that it can directly and indirectly perform, the Boost libraries use it as the basis for their lexical_cast and lexical_convert functionality. It is quite powerful.

Google can find many good tutorials on useful ways to use the class, such as this one.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I occasionally write about assorted stuff.

### #3Vortez  Members

Posted 26 January 2014 - 06:39 AM

In C, there is also itoa().

### #4Álvaro  Members

Posted 26 January 2014 - 08:14 AM

I just want to mention that itoa() is not a standard function. The standard way to do this in C99 is snprintf(buffer, buffer_length, "%x", number)'.

### #5Psychopathetica  Members

Posted 26 January 2014 - 10:04 AM

But the thing is that all those methods still involve the console window. If you were wanting to save it to file, or a listbox, label, or messagebox, couldn't you use sprintf() to put the result in a string and display it using any of those?

[EDIT]

Seems like Im right:

#include <windows.h>
#include <string>
using namespace std;

int main()
{
int number = 11;
string Text[255];
sprintf((char *)Text, "The hexadecimal value of number is: %x", number);
MessageBox(NULL, (char *)Text, "typedef", MB_OK);

return 0;
}


And although it works on VS 2012, I tried it on VS 2013, and I got a warning saying it might be unsafe, use sprintf_s instead. Very strange. And even then the console window crashes afterwards no matter which sprintf I use.

As an experiment I even tried not using a Messagebox, and displayed it in the console window. It works until I close the console window, then crashes. Its only if I comment out the sprintf_s that it doesnt crash:

#include <windows.h>
#include <string>
#include <iostream>
using namespace std;

int main()
{
int number = 11;
string Text[255];
sprintf_s((char *)Text, sizeof(Text),"The hexadecimal value of number is: %x", number);
//MessageBox(NULL, (char *)Text, "typedef", MB_OK);
cout << (char *)Text << endl;
system("pause");
return 0;
}


Edited by Psychopathetica, 26 January 2014 - 10:16 AM.

### #6haegarr  Members

Posted 26 January 2014 - 10:15 AM

POPULAR

But the thing is that all those methods still involve the console window.

Err, no! Each of the above mentioned

* snprintf() ((which is just a variant of sprintf() so that the amount of characters written can be limited))

use a string or char[] as target; none of them involve the console window (I assume you mean the implicit use of stdout / stderr here).

Edited by haegarr, 26 January 2014 - 10:17 AM.

### #7Brother Bob  Moderators

Posted 26 January 2014 - 10:31 AM

POPULAR

And although it works on VS 2012, I tried it on VS 2013, and I got a warning saying it might be unsafe, use sprintf_s instead. Very strange. And even then the console window crashes afterwards no matter which sprintf I use.

As an experiment I even tried not using a Messagebox, and displayed it in the console window. It works until I close the console window, then crashes. Its only if I comment out the sprintf_s that it doesnt crash:

You are creating an array of 255 string objects, and your call to printf overwrites the string objects with, as far as the string objects are concerned, garbage data. When the array is destroyed, some of the 255 the string objects have been trashed and teh destructor fails.

If you want to use the printf-family of functions, then either create an array of 255 characters, or one string object that contains room for 255 characters (and be sure to get a pointer to the internal string data, don't overwrite the string object). But 255 string objects that you overwrite with character data is totally wrong.

### #8Wooh  Members

Posted 26 January 2014 - 10:33 AM

Psychopathetica, it crash because Text is an array of std::string when it should have been an array of char.

### #9Psychopathetica  Members

Posted 26 January 2014 - 11:30 AM

Setting char *Text instead of string Text[255] still crashes the console window. But this works at least:

#include <windows.h>
#include <string>
#include <iostream>
using namespace std;

int main()
{
int number = 11;
char Text[255];
sprintf_s(Text, sizeof(Text), "The hexadecimal value of number is: %x", number);
MessageBox(NULL, Text, "typedef", MB_OK);
cout << (char *)Text << endl;
system("pause");
return 0;
}


However I still wanna be able to store the data in a string rather than a char.

Edited by Psychopathetica, 26 January 2014 - 11:33 AM.

### #10haegarr  Members

Posted 26 January 2014 - 11:57 AM

POPULAR

Setting char *Text instead of string Text[255] still crashes the console window.

For the case that your console application does not load the correct libraries: Have you considered to use one of the suggested standardized functions (sprintf, snprintf) instead?

However I still wanna be able to store the data in a string rather than a char.

The very first answer above already told the solution. In case that your favorite search engine has a defect … something like the following should do (but is written down untested):

stringstream myHexString;
myHexString << hex << number;
string str = myHexString.str();


Edited by haegarr, 26 January 2014 - 12:12 PM.

### #11incertia  Members

Posted 30 January 2014 - 09:59 AM

Why not just convert to base 16 (hex) by yourself? The math is not that hard (num % 16, num /= 16).
See here.
what

### #12Álvaro  Members

Posted 30 January 2014 - 10:24 AM

It's not that hard, but it's still tricky to get the code right. Try writing the function yourself and post it here.

Posted 30 January 2014 - 04:34 PM

Here's some completely untested code that should do the trick. It should be equivalent to the much simpler sprintf(result, "%08x", value);

I don't think it's especially tricky to write. It's not so easy to read and understand though.

Spoiler

### #14Álvaro  Members

Posted 30 January 2014 - 07:51 PM

That code does look pretty good. It's not exactly equivalent to the sprintf call, because you are using capital letters.

### #15Servant of the Lord  Members

Posted 30 January 2014 - 08:16 PM

This is the function I use:
std::string UnsignedIntToHexString(uint32_t value, const std::string &prefix = "0x", size_t digits = 8, bool uppercase = true)
{
return UnsignedIntToHexString((uint64_t)value, prefix, digits, uppercase);
}

//Converts an integer to a std::string, in hexadecimal format. 'digits' is the fixed number of digits that show up.
//For example, 0x00FF00AA shows zeroes if 'digits' is 8, and only shows 0x00AA, if 'digits' is 4.
std::string UnsignedIntToHexString(uint64_t value, const std::string &prefix = "0x", size_t digits = 16, bool uppercase = true)
{
const char *symbols = (uppercase? "0123456789ABCDEF":"0123456789abcdef");

//Fill everything with zeroes (including the digits above the first 8 digits).
std::string result((prefix.size() + digits), '0');

//I'm kinda cheating here. If we have less than 8 digits, we intentionally are subtracting
//from 'startIndex'. For example, if we have 6 digits, we subtract 2 from the starting index,
//because 'case 6' in the switch statement lower down this function adds 2 to the index.
const size_t startIndex = prefix.size() + (int(digits) - 16);
digits %= 16; //This is a 64 bit number, so any digit above 16 leave as zero.

//Write the prefix, if there is one.
if(!prefix.empty())
{
result.replace(0, prefix.size(), prefix);
}

/*
Each 'digit' of a hexadecimal number is 4 bits (2^4 = 16).

First, shift the 4 bits we want over to the far-right side of the number.
(value >> 28)

Second, mask the value, so it's *only* those 4 bits (a value between 0 and 15)
((...) & 0x0F)

Finally, use that value to lookup the symbol in the symbol array.
symbols[ ... ]
*/
switch(digits)
{
//I am intentionally using case-statement fall-through here.
case 16: result[startIndex + 0] = symbols[((value >> 60) & 0x0F)];
case 15: result[startIndex + 1] = symbols[((value >> 56) & 0x0F)];
case 14: result[startIndex + 2] = symbols[((value >> 52) & 0x0F)];
case 13: result[startIndex + 3] = symbols[((value >> 48) & 0x0F)];
case 12: result[startIndex + 4] = symbols[((value >> 44) & 0x0F)];
case 11: result[startIndex + 5] = symbols[((value >> 40)  & 0x0F)];
case 10: result[startIndex + 6] = symbols[((value >> 36)  & 0x0F)];
case 9: result[startIndex +  7] = symbols[((value >> 32)  & 0x0F)];
case 8: result[startIndex +  8] = symbols[((value >> 28) & 0x0F)];
case 7: result[startIndex +  9] = symbols[((value >> 24) & 0x0F)];
case 6: result[startIndex + 10] = symbols[((value >> 20) & 0x0F)];
case 5: result[startIndex + 11] = symbols[((value >> 16) & 0x0F)];
case 4: result[startIndex + 12] = symbols[((value >> 12) & 0x0F)];
case 3: result[startIndex + 13] = symbols[((value >> 8)  & 0x0F)];
case 2: result[startIndex + 14] = symbols[((value >> 4)  & 0x0F)];
case 1: result[startIndex + 15] = symbols[((value >> 0)  & 0x0F)];
default: break;
}

return result;
}
And binary:
//Converts an integer to a std::string, in binary format. 'digits' is the fixed number of digits that show up.
//'blockSize' is the number of characters before being seperated by 'seperator' (usually a space or a hyphen).
std::string UnsignedIntToBinaryString(uint32_t value, size_t digits = 32, size_t blockSize = 0, char seperator = '-')
{
return UnsignedIntToBinaryString((uint64_t)value, digits, blockSize, seperator);
}

std::string UnsignedIntToBinaryString(uint64_t value, size_t digits = 64, size_t blockSize = 0, char seperator = '-')
{
//A blockSize of 0 means someone probably wanted a single block of every digit.
if(blockSize == 0) blockSize = digits;
if(digits == 0) digits = 64; //A 64 bit variable, to show it fully, requires 64 digits.

//Figure out how many seperators we'll have.
//We subtract one, if a seperator will land on the very end.
size_t numSeperators = (digits / blockSize) - ((digits % blockSize) == 0? 1 : 0);

//Allocate our entire string in advance.
std::string result(digits + numSeperators, '#');

size_t seperatorCountdown = blockSize;
for(size_t i = result.size(); i--> 0; )
{
result[i] = ((value & 1) ? '1': '0');
value >>= 1; //Shift the bits over one spot.

//Add a seperator if our countdown reaches 0, unless we are at the end of the number.
if(--seperatorCountdown == 0 && i != 0)
{
result[--i] = seperator;
seperatorCountdown = blockSize;
}
}

return result;
}
I *think* I wrote those functions myself (it's been awhile, and usually I add a comment with the source if it wasn't written by me), but I got the idea of the array of symbols + lookup index from someone else's code. I definitely wrote the binary one.

Note that the hexadecimal one doesn't loop, so it's (needlessly) lightning fast. Sometimes I optimize string formatting functions just for the heck of it, as code warm-ups when I'm procrastinating or just getting back into coding after a break.

Edited by Servant of the Lord, 30 January 2014 - 08:19 PM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #16TheComet  Members

Posted 31 January 2014 - 02:18 AM

Can someone tell me why we aren't using the stringstream solution provided by frob again?

#include <iostream>
#include <sstream>

int main()
{

// conversion to hex string
std::stringstream ss; ss << std::hex << myNumber;
std::string myHexString = ss.str();

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



OP specifically requested:

[...] the string data type from the library #include <string>
Is it possible without having to design my own hex to string conversion function?

If you need upper case, you can add:

#include <algorithm>
std::transform( myHexString.begin(), myHexString.end(), myHexString.begin(), ::toupper );


And if you need the "0x" prefix you can do that in the string stream or insert it into the string after converting to upper case:

ss << "0x" << std::hex << myNumber; // either this
myHexString.insert( 0, "0x" ); // or this


Edited by TheComet, 31 January 2014 - 02:27 AM.

"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty

### #17Servant of the Lord  Members

Posted 31 January 2014 - 06:45 PM

Can someone tell me why we aren't using the stringstream solution provided by frob again?

Because, to do a simple thing, you have to write several lines of code.
void FuncWantingAString(std::string hexString);

int main()
{
int value = 0xBEEF;

//Single-func:
FuncWantingAString(UnsignedIntToHexString(value));

//String-stream:
std::stringstream ss;
ss << std::hex << myNumber;
FuncWantingAString(ss.str());
}
One job (convert from int to string) should be one function call, IMO.
Stringstream is nice for formatting a larger text string with multiple values... but for a single conversion, a function is much nicer. C++11 added std::to_string(), but they probably should have allowed you to pass in a format as an optional parameter.
It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #18ApochPiQ  Moderators

Posted 31 January 2014 - 06:54 PM

Simple solution:

std::string UnsignedIntToHexString (unsigned value) {
std::string ret;
std::ostringstream format;
format << std::hex << value;
ret = format.str();

return ret;
}

Wielder of the Sacred Wands

### #19Servant of the Lord  Members

Posted 31 January 2014 - 07:07 PM

Exactly. Alternatively:
//Converts an integer into a std::string, in the base 'base'.
std::string IntToStringBase(uint32_t value, Base base)
{
std::stringstream stream;

if(base == Base::Octal) stream.setf(std::ios_base::oct, std::ios_base::basefield);
else if(base == Base::Hexadecimal) stream.setf(std::ios_base::hex, std::ios_base::basefield);
else stream.setf(std::ios_base::dec, std::ios_base::basefield);

stream << value;

return stream.str();
}

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #20Trienco  Members

Posted 01 February 2014 - 11:41 PM




And if you need the "0x" prefix you can do that in the string stream or insert it into the string after converting to upper case:

ss << "0x" << std::hex << myNumber; // either this
myHexString.insert( 0, "0x" ); // or this
`

Or simply:

ss << std::showbase << std::hex << myNumber;

Which has the distinct advantage that you don't have to manually add the 0x to every single hex value.

f@dzhttp://festini.device-zero.de

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.