To store the color of a button's text, I have the variable uint32_t textColor
set to the value 0xF5CE52 (0d16109138). Now I need to insert this value of textColor into a string as a hexadecimal value. However, when I try to convert textColor to a hex string via a stringstream, it seems like a thousands separator is inserted in the hex string and I can't figure out how to prevent this from happening...
To convert textColor to a hexadecimal string, I'm using the following piece of code:
uint32_t textColor = 0xF5CE52;
stringstream btnColorHex;
btnColorHex << uppercase << setfill('0') << setw(6) << hex << textColor;
I print it using the following:
cout << "btnColorHex.str() - " << btnColorHex.str() << endl;
Which results in the following output:
btnColorHex.str() - F5C.E52
Note: I have set my system locales to format numbers in Dutch formatting, which uses . as the thousands separator and , as the decimal separator.
I expected the following to be printed to the console:
btnColorHex.str() - F5CE52
I had 'solved' this issue by removing the . from the string afterwards, but of course this didn't work when I tested this code on a PC with the locales set to American formatting using , as the thousands separator.
I have also tried casting the uint32_t
to an unsgined int
, but that resulted in the same issues.
I could try using functions like sprintf()
from plain C to circumvent this issue, but I'd like to now if there is a proper C way to do this first.
So my question is: Is there a way in C to format an unsigned integer as a hex string, without it inserting a thousands separator?
CodePudding user response:
To disable the locale formating use imbue(std::locale("C"))
Your code will now look like this:
uint32_t textColor = 0xF5CE52;
stringstream btnColorHex;
btnColorHex.imbue(std::locale("C"));
btnColorHex << uppercase << setfill('0') << setw(6) << hex << textColor;
Now regardless of the PC's locale the output will always be formatted correctly:
btnColorHex.str() - F5CE52
CodePudding user response:
You could just handwrite this as
#include <cstdint>
#include <cstdlib>
#include <iostream>
std::string hex( uint32_t value ) {
char str[16];
char* p = &str[16];
do {
p--;
uint32_t digit = value % 16;
value /= 16;
*p = digit>=10 ? 'a' (digit-10) : '0' digit;
} while ( value > 0 );
p--;
*p = 'x';
p--;
*p = '0';
return std::string(p,&str[16]-p);
}
Running as
int main()
{
for ( int j=0; j<10; j ) {
uint32_t value = std::rand();
std::cout << std::hex << value << " " << hex( value ) << std::endl;
}
}
Produces
6b8b4567 0x6b8b4567
327b23c6 0x327b23c6
643c9869 0x643c9869
66334873 0x66334873
74b0dc51 0x74b0dc51
19495cff 0x19495cff
2ae8944a 0x2ae8944a
625558ec 0x625558ec
238e1f29 0x238e1f29
46e87ccd 0x46e87ccd
Godbolt: https://godbolt.org/z/xxEnqs7es
Another option is to use C 20's std::format
. However at the moment only gcc/clang on trunk (unreleased) have this feature implemented.
#include <format>
std::string hex( uint32_t value ) {
return std::format("0x{:x}", value);
}
Godbolt: https://godbolt.org/z/roMc5ajcj