Christian Stewart
Christian Stewart

Reputation: 15519

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?

Upvotes: 3

Views: 2328

Answers (1)

paxdiablo
paxdiablo

Reputation: 881463

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]));

Upvotes: 8

Related Questions