Search code examples
c++boostformathexboost-format

Odd behavior in boost::format hex


I'm trying to format a binary array: char* memblock to a hex string.

When I use the following:

fprintf(out, "0x%02x,", memblock[0]);

I get the following output:

0x7f,

When I try to use boost::format on an ofstream like so:

std::ofstream outFile (path, std::ios::out); //also tried with binary
outFile << (boost::format("0x%02x")%memblock[0]);

I get a weird output like this (seen in Vi): 0x0^?.

What gives?


Solution

  • Given that the character for 0x7f is CTRL-?, it looks like it's outputting the memblock[0] as a character rather than a hex value, despite your format string.

    This actually makes sense based on what I've read in the documentation. Boost::format is a type-safe library where the format specifiers dictate how a variable will be output, but limited by the actual type of said variable, which takes precedence.

    The documentation states (my bold):

    Legacy printf format strings: %spec where spec is a printf format specification.

    spec passes formatting options, like width, alignment, numerical base used for formatting numbers, as well as other specific flags. But the classical type-specification flag of printf has a weaker meaning in format.

    It merely sets the appropriate flags on the internal stream, and/or formatting parameters, but does not require the corresponding argument to be of a specific type. e.g. : the specification 2$x, meaning "print argument number 2, which is an integral number, in hexa" for printf, merely means "print argument 2 with stream basefield flags set to hex" for format.

    And presumably, having the field flag set to hex doesn't make a lot of sense when you're printing a char, so it's ignored. Additionally from that documentation (though paraphrased a little):

    The type-char does not impose the concerned argument to be of a restricted set of types, but merely sets the flags that are associated with this type specification. A type-char of p or x means hexadecimal output but simply sets the hex flag on the stream.

    This is also verified more specifically by the text from this link:

    My colleagues and I have found, though, that when a %d descriptor is used to print a char variable the result is as though a %c descriptor had been used - printf and boost::format don't produce the same result.

    The Boost documentation linked to above also explains that the zero-padding 0 modifier works on all types, not just integral ones, which is why you're getting the second 0 in 0x0^? (the ^? is a single character).


    In many ways, this is similar to the problem of trying to output a const char * in C++ so that you see a pointer. The following code:

    #include <iostream>
    int main() {
       const char *xyzzy = "plugh";
       std::cout << xyzzy << '\n';
       std::cout << (void*)xyzzy << '\n';
       return 0;
    }
    

    will produce something like:

    plugh
    0x4009a0
    

    because the standard libraries know that C-style strings are a special case but, if you tell them it's a void pointer, they'll give you a pointer as output.

    A solution in your specific case may be just to cast your char to an int or some other type that intelligently handles the %x format specifier:

    outFile << (boost::format("0x%02x") % static_cast<int>(memblock[0]));