7

The Boost Format documentation says:

One of its goal is to provide a replacement for printf, that means format can parse a format-string designed for printf, apply it to the given arguments, and produce the same result as printf would have.

When I compare the output of boost:format and printf using the same format string I get different outputs. Online example is here

#include <iostream>
#include <boost/format.hpp>

int main()
{
    boost::format f("BoostFormat:%d:%X:%c:%d");

    unsigned char cr =65; //'A'
    int cr2i = int(cr);

    f % cr % cr % cr % cr2i;

    std::cout << f << std::endl;
    printf("Printf:%d:%X:%c:%d",cr,cr,cr,cr2i);
}

The output is:

BoostFormat: A:A:A:65

printf: 65:41:A:65

The difference is when I want to display a char as integral type.

Why there is a difference? Is this a bug or wanted behavior?

Florian Winter
  • 4,750
  • 1
  • 44
  • 69
ToBe
  • 921
  • 1
  • 9
  • 23

2 Answers2

6

This is expected behaviour.

In the boost manual it is written about the classical type-specification you uses:

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.

Please note also, that in the stdlib-printf call all char arguments are automatically converted to int due to the vararg-call. So the generated code is identical to:

printf("Printf:%d:%X:%c:%d",cr2i,cr2i,cr2i,cr2i);

This automatic conversion is not done with the % operator.

jofel
  • 3,297
  • 17
  • 31
  • 1
    +1 But, wow, that's horrible. I wonder what's their reasoning for this is? It seems they took C style format (which isn't great to begin with) and yet still did not make it backwards compatible. Like picking worse of both worlds. – user694733 Nov 20 '15 at 09:57
  • Thanks your answer. Good to know that is expected behavior, however it was not what I expected. Here, the actual type overrules the specifier. So for char it makes no difference between '%d' und '%c', Strange – ToBe Nov 20 '15 at 10:05
  • @user694733: Boost.Format cannot change the (compile-time) overloading of `operator%` based on the (run-time) contents of the format string. Now you can hide the problem, but that does add significant complexity - you'd have to do implement the _possible_ overload scenarios at compile time, and choose the correct one at runtime. This isn't space-efficient either. – MSalters Nov 20 '15 at 16:06
  • @joefel In your code you haven't actually written code that matches the behaviour of what you want to output. If you wanted to match to the printf behaviour what you should have written is `f % +cr % +cr % cr % +cr;` – Peter Nimmo Sep 13 '16 at 12:03
  • 1
    This is using the unary + operator to perform Integral promotion - see https://msdn.microsoft.com/en-us/library/ewkkxkwb(d=hv.2,v=vs.140).aspx for details – Peter Nimmo Sep 13 '16 at 12:06
0

Addition to the accepted answer:

This also happens to arguments of type wchar_t as well as unsigned short and other equivalent types, which may be unexpected, for example, when using members of structs in the Windows API (e.g., SYSTEMTIME), which are short integers of type WORD for historical reasons.

If you are using Boost Format as a replacement for printf and "printf-like" functions in legacy code, you may consider creating a wrapper, which overrides the % operator in such a way that it converts

  • char and short to int
  • unsigned char and unsigned short to unsigned int

to emulate the behavior of C variable argument lists. It will still not be 100% compatible, but most of the remaining incompatibilities are actually helpful for fixing potentially unsafe code.

Newer code should probably not use Boost Format, but the standard std::format, which is not compatible to printf.

Florian Winter
  • 4,750
  • 1
  • 44
  • 69