Home > Back-end >  C How to convert an unsigned integer to a hex string without a thousands separator
C How to convert an unsigned integer to a hex string without a thousands separator

Time:01-27

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

  • Related