Survey of existing libraries
Microsoft
- The standard
printf
family does not support POSIX positional arguments. The _printf_p
family does. n
conversion specifier is not supported by default. (Neither by Stannum.Printf.) - The non-standard length modifiers
I
, I32
and I64
supported by Microsoft are not supported by Stannum.Printf. - Floating point output is not standard conforming;
- Uses three digits for the exponent in scientific form by default.
- Formats infinity and NaN values in Microsoft’s own manner.
Code |
const double inf = std::numeric_limits<double>::infinity();
const double nan = std::numeric_limits<double>::quiet_NaN();
printf("%g\n%g\n%.4g\n%.3g\n%.2g\n%.1g\n%g\n", 1e6, inf, inf, inf, inf, inf, nan);
|
Microsoft output | Standard output |
1e+006
1.#INF
1.#IO
1.#J
1.$
1
1.#QNAN | 1e+06
inf
inf
inf
inf
inf
nan |
Note: the implementation may use infinity or nan(n-char-sequence) for the last six values. |
Boost.Format
- Boost.Format introduces plenty of non-standard extensions. The following extension by boost are not supported by Stannum.Printf:
%|spec|
format specification, %{nt}
— absolute tabulation, =
— centered alignment, and _
— internal alignment. - Rationale:
- Using spaces for aligning output, as well as determining visual string length based on either
char
or code point count, results in broken code. This is true even for fixed width fonts and terminals. One must communicate with the rendering engine to get the visual length of the string. The POSIX wcwidth
function should be used when writing to terminals. If the output goes to a file that will be opened by the user later and you want it to be formatted nicely, consider outputting HTML or equivalent.
- On the other hand boost does not support the following standard features:
- precision for integer conversions,
h
and hh
for casting the argument to short
and char
, and *
and *n$
for setting the width and precision from an argument.
- space flag is broken when used in conjunction with
group()
. - Unlike boost, Stannum.Printf decides the formatting based on the conversion specifier and then checks that the type of the corresponding argument is compatible, not vice versa. Thus
cout << boost::format("%d") % "abc";
harmlessly prints abc
, whereas stannum::io::printf(cout, "%d", "abc");
throws a ‘type mismatch’ exceptions, if enabled. See the fourth principle in the introduction. - Boost.Format is the slowest library on Earth.
…the best C++ output/formatting library you’ll ever use.
- …I would call it ‘a utility for concatenating, reordering and padding strings’. Does this job quite well.
- Anything more complicated, like formatting, is done by passing an already formatted strings to FastFormat.
- Comes with a set of functions to format those strings. E.g.:
ff::fmt(buf, "The address is {0} above normal.\n", ff::to_x(address, -width, prec));
- Octal and most of the
printf
flags do not have analogies in the set of formatting functions provided. - The flexibility of C/POSIX printf can be theoretically achieved at the cost of verbosity.
- For floating point formatting requires precision ≤ width for no apparent reason. [ Note: Even if precision > width, the resulting string may have fewer digits due to the zeros being trimmed, in which case padding may be desired. —end note ]
- Proprietary format string syntax.
- Uses process-wide locks for caching parsed format strings.
Loki SafeFormat
- A type safe wrapper over C
printf
, plus uses operator <<(ostream&, T)
for user types. - Does not compile for 64-bit architecture.
- Zero precision for integers not supported.
- Dynamic width/precision for floating point crashes.
- Bugous format string parsing.
- To be fair, it is quite good for an unfinished project.
ts_printf
Extremely Efficient Type-safe printf Library
- Verbose call syntax compared to plain old
printf
. - Proprietary format string syntax.
- Does not support dynamic field width.
- Does not support precision for integers.
- Does not support internal zero padding.
- Does not have a base indicator for octals.
- Homegrown floating point formatting routine which
- does not support floating point in scientific form,
- breaks on infinities, NaNs, and large values like 3e+30,
- incorrectly rounds, and, in particular,
- does not satisfy the internal identity requirement.
- Heavily templated with slow compile times. Uses C++11 everywhere — where needed and not needed.
- Conversion specifiers become extremely long, e.g. something simple like
%#8x
becomes {0w8arb016x}
.
External links