This is an implementation of printf for C++11.
l are accepted but mostly ignored, since the typechar16_t and char32_t character andIn C, the functions from the printf() family are used for formatted
text output and string formatting.
C++ replaced this with the type-safe output stream model and its <<
operator, which offers the same formatting options but in a much more
verbous way.
This library implements the well-known printf() interface for C++,
with full type safety. It supports all the format strings of the
standard C library printf(), plus Posix extensions like positional
arguments. Example syntax:
// Write to stream
std::cout << xprintf("%d: %f", 1, 5.7) << std::endl;
// Format to string
std::string s = xprintf("Result: %d", 42);
// Or to wide character string
std::wstring w = xprintf("Question: how much, %s", s);
// Default: output goes to standard output
xprintf("%s\n", w);
Unpack the distribution to a directory on your local machine. You can
include the proper header in subdirectory include/xprintf from your
program. To make inclusion of the headers easier, it is recommended
to add the subdirectory include of the Xprintf distribution to the
include file search path of the compiler. This is commonly achieved
with the option -I/path/to/xprintf/include (assuming that the
xprintf distribution has been upacked to directory
/path/to/xprintf). Then you can include the xprintf headers through
their standard names like "xprintf/xprintf.h".
In order to use Xprintf, the proper headers have to be
included. These are:
// Normal xprintf() header:
#include "/path/to/xprintf/include/xprintf/xprintf.h"
// For use with FILE* as stream argument:
#include "/path/to/xprintf/include/xprintf/xprintf_file.h"
// For the standard function names like printf() and fprintf();
#include "/path/to/xprintf/include/xprintf/xprintf_std.h"
If the xprintf include directory /path/to/xprintf/include has been
added to the include file search path of the compiler, e.g. using the
compiler option -I/path/to/xprintf/include, this is reduced to:
#include "xprintf/xprintf.h"
using namespace XPrintf;
The xprintf() functions are exported through namespace XPrintf. It
is recommented to make them available via a using namespace
directive like in the example above. Alternatively it is possible to
import the functions xprintf() and sxprintf() separately through
using declarations:
using XPrintf::xprintf;
using XPrintf::sxprintf; // Optional
Header "xprintf/xprintf_std.h" defines the C standard library names
fprintf(), printf(), snprintf(), sprintf(), fwprintf(), wprintf() and
swprintf() in namespace XPrintfStd. To import them into your
working namespace, you can again use a using namespace directive:
#include "xprintf/xprintf_std.h"
using namespace XPrintfStd;
printf("Hello, world!\n");
This makes all the standard library names available through their
standard names.
Xprintf() is pre-configured for header-only use. This means: Just
include the proper header and you are done. In order to reduce space
overhead and compilation time, a precompiled library can be used.
See section Creating a Library.
Xprintf internally uses the included StrCvt
library for character type conversions of arguments and destination
strings. If you want to use the StrCvt package
directly, look there for information about StrCvt headers and
namespaces.
The most flexible way to use xprintf() is through the call
xprintf(format, args...). The expression xprintf(format, args...)
can be used as follows:
operator<<, which writes thestring or wstring, which receives theThe diffent usages are shown here:
// Write to stream:
std::cout << xprintf("%d: %f", 1, 5.7) << std::endl;
// Or to wide stream:
std::wcout << xprintf("%d: %f", 1, 5.7) << std::endl;
// Format to string:
std::string s = xprintf("Result: %d", 42);
// Or to wide character string:
std::wstring w = xprintf("Question: how much, %s", s);
// Default: output goes to standard output (can be redirected)
xprintf("%s\n", w);
// Using a wide character format works as well.
xprintf(L"%s\n", w);
// Redirect to another stream:
xprintf(std::wcerr);
// Now by default all output goes to std::wcerr
xprintf("%s\n", w);
Narrow and wide character types, strings and streams can be freely mixed:
char or a wchar_t character string constantstring or wstring.Generally all argument strings are converted (using the included
StrCvt library) according to the conversion rules of
the currently installed global locale. For this conversion, narrow
character strings are treated as locale-defined characters. If
strings are known to be in UTF-8 format instead of the locale-defined
character format, they can be defined as type StrCvt::u8string.
Xprintf recognizes this string type and transforms these arguments
according to the UTF transformations.
If xprintf() is called with only a stream argument like above in
xprintf(std::wcerr), this stream becomes the default stream instead of
the standard output.
An output stream can be passed to xprintf() as the first
argument. Then the output is sent to this stream, and xprintf()
returns the number of characters formatted (which may differ from the
number of bytes written if e.g. the format is a wide character format
and the stream a narrow char stream).
// Write to stream:
int count = xprintf(std::cout, "%d: %f\n", 1, 5.7);
// Or to wide stream:
count = xprintf(std::wcerr, "%d: %f\n", 1, 5.7);
If the header "xprintf/xprintf_file" has been included, xprintf()
works identically with FILE* streams like stdout and stderr. This
call is equivalent to the standard C function fprintf().
While the result of xprintf() can be assigned to a string or a
wstring, it isn't one. To pass the result to a function as a string
argument, the conversion might need to be done by an explicit call to
the string constructor.
The function sxprintf(format, args...) returns a string directly. The
default string type (string or wstring) is determined by the width
of the format argument. It can be overridden by a template argument.
// Convert result of xprintf(format, args...) to a string
my_fun(std::string(xprintf("Result is %d", 42)));
// Simpler: use sxprintf(format, args...)
my_fun(sxprintf("Result is %d", 42));
// Pass wstring to my_fun(), using template argument
my_fun(sxprintf<std::wstring>("Result is %d", 42));
// Equivalent: use wchar_t format
my_fun(sxprintf(L"Result is %d", 42));
Using sxprintf(format, args...) should in theory be a little bit
faster than the otherwise equivalent form `std::string(xprintf(format,
args...)) since no proxy has to be created.
Xprintf is preconfigured for header-only use. This means: Just
include the proper header and you are done. In order to reduce space
overhead and compilation time, a precompiled library can be used.
The main advantage in using a library is that each time the xprintf
header is included, the compiler need not look at the implementation
details. This can speed up compilation significantly.
To create the library, the C++ source files libxprintf.cpp and
libxprintf_file.cpp in directory lib of the distribution must be
compiled. Under Linux, just run make. Before compiling, you may
want to select the compiler to use: Uncomment to proper CXX= - line
in the toplevel Makefile.template. Running make should create a
library lib/libxprintf.a, which has to be linked to the programs.
In Visual C++, instead of building a library, you may just add the
library source files to your project.
In order to make the header use the library, you must open the header
xprintf/xprintf.h with an editor and change the preprocessor symbol
XPRINTF_IMPL_USE_LIBRARY from 0 to 1. The next time a program is
compiled, the library will be used. You can check that the library is
used as intended by omitting the library when linking. Linking should
fail with missing externals.
In order to run the tests, the headers for the boost test framework
are required.
All portable standard C printf() formats are supported and should
yield the identical result as with the standard C printf().
Most Posix printf() extensions like positional arguments are supported.
The following additional format declarators are supported:
%B formats boolean values, flag # disables boolalpha
%m formats monetary values, flag # shows currency sign
%M formats monetary values, flag # shows international currency name
The char type used internally for formatting is determined by the
format char type. The result should not be affected (besides the
character count returned). Wide and narrow format strings, output
streams, strings and arguments can be freely mixed. Arguments are
converted to the format char type as needed, and the result is
converted to proper stream or string type used.
Xprintf() has been tested with:
Xprintf writes output to a (wide or narrow) output stream under
control of a (wide or narrow) format string that specifies how the
remaining arguments are converted. If there are insufficient
arguments for the format, the program is terminated through a call to
assert() describing the problematic format string.
Characters other than % in the input stream are copied unchanged to
the output stream.
The character % begins a conversion specification. A conversion
specification consists of the following parts:
An optional argument number specifier in the form n$, with n a
decimal integer number denoting the index (after the format string)
of the argument to be formatted. If the argument number specifier
is missing, the next consecutive argument is formatted.
Zero or more optional flags in the form of the characters -,
+, space, #, 0 or '.
An optional minimum field width in the form of a decimal number,
an asterisk * or *n$ with n a decimal integer number denoting
an argument index (see below). If the converted value requires less
width than the specified number of space characters, it is padded
with space characters on the left side (by default) or on the
right side if the left adjustment flag - has been specified.
An optional precision in the form of a period . followed by an
decimal number, an asterisk * or *n$ with n a decimal integer
number (see below).
An optional argument size modifier in the form hh, h, l,
ll, j, z, t or L.
A final conversion specifier that specifies the type of the conversion to
be applied.
As noted above, the field width and the precision may be indicated
by an asterisk *, in which case the next argument in sequence
(before the value to be converted) must contain an integral number
specifying the value. A negative field width implies a - flag. If
the form *n$ is used, the decimal integer n gives the index of the
argument (after the format) containing the width or precision.
The flags and their meanings are:
- Left-justify the result of the conversion. If this flag is
not specified, the conversion is right-justified.
+ Format a positive value with a + sign. If this flag is not
specified, the sign is omitted for positive values.
space For a positive value, output a space at the place of the
sign. If the space and + flags both appear, the space flag
is ignored.
# The result is converted in an alternative form. For o, x and
X conversion specifiers, the number is prefixed by 0, 0x or
0X. For f, F, e, E, g, G, a and A conversion, the
result is always formatted with a decimal point character, even if
no digits follow it. For g and G conversions, trailing zeros
are not removed from the result. For the bool conversion specifier
B, write 0 or 1 instead of false and true. For the
monetary conversion specifiers, write the currency symbol.
0 Use leading zeros to pad to the field width instead of spaces.
' Insert thousands separators. This flag is accepted for
compatibility with the X/Open printf() specification but ignored by
xprintf(). Insertion of thousands separators is dependent on the
locale.
The argument size modifiers denote that the argument to be formatted
is a (signed or unsigned) char for hh, short for h, long for
l, long long for ll, intmax_t for j, size_t for z,
ptrdiff_t for t or long double for L. They are supported for
compatibility with the C version of printf() but mostly ignored by
xprintf(). Xprintf() gets this information from the type of the
arguments. The h and hh argument size specifiers are used with
the conversions specifiers o, x and X to mask leading bits from
signed numbers. The l argument size specifier is used with
conversion specifier c to convert a wide character.
The conversion specifiers and their meanings are:
d, i, uFormat the argument as a decimal integer. These conversion
specifiers are equivalent, signedness is determined from the type of
the argument. The argument must be of a signed or unsigned integral
or a floating point type. The precision specifies the minimum
number of digits.
o, x, XFormat the argument as a octal or hexadecimal number. Specifier X
uses uppercase hexadecimal letters. The argument must be of a
signed or unsigned integral type, a floating point type or a pointer
type. The precision specifies the minimum number of digits.
f, FFormat the argument in plain floating point style [-]dddd.ddd. The
precision specifies the number of digits to the right of the decimal
point and defaults to 6. The argument must be of a floating point
type or a signed or unsigned integral type.
e, EFormat the argument in scientific floating point style
[-]d.dddddde[+/-]dd. The precision specifies the number of digits
to the right of the decimal point and defaults to 6. The argument
must be of a floating point type or a signed or unsigned integral
type.
g, GFormat like the e or E specifier if the exponent is less than -4
or greater than or equal to the precision, else format like the f or
F specifier.
a, AFormat the argument in hexadecimal floating point style
[-]0xh.hhhhhhp[+/-]d. The precision specifies the number of digits
to the right of the decimal point and defaults to the number of
digits necessary to exactly represent the argument. The argument
must be of a floating point type or a signed or unsigned integral
type.
c, CConvert to a single character. If C is used or the argument size
specifier l is present, the argument is interpreted as a wide
character. Else the argument is truncated to char. The argument
must be of a signed or unsigned integral type.
s, SFormat the argument as a string of characters. The argument must be
a C++ string type (std::string, std::wstring, std::u16string
or std::u32string) or a C style null-terminated char, wchar_t,
char16_t or char32_t character pointer string. For the C++
string types, the precision specifies the maximum number of Unicode
characters to output. For the C style null-terminated character
pointer string types, the precision specifies the maximum length of
the string; if no null-character is found after this number of
source characters, precision source characters are output. For
padding, the width of the formatted string is estimated from the
Unicode characters using Markus Kuhn's mk_wcswidth().
Generally all argument strings are converted (using the included
StrCvt library) according to the conversion rules
of the currently installed global locale. For this conversion,
narrow character strings are treated as locale-defined characters.
If strings are known to be in UTF-8 format instead of the
locale-defined character format, they can be defined as type
StrCvt::u8string. Xprintf recognizes this string type and
transforms these arguments according to the UTF transformations.
pFormat the argument in an implementation-defined pointer format.
The argument must be a pointer or a signed or unsigned integral
type.
BFormat the argument as a bool. The argument must be a bool, a
signed or unsigned integral type, a floating point type or a pointer
type.
m, MFormat the argument as a locale-dependent monetary value.
Declarator M uses the international currency symbol. Note that in
order to write the currency symbol, flag # must be specified.
The argument must by a signed or unsigned integral type or a
floating point type.
nDo not output the argument but write the number of characters
converted up to this point to the argument. The argument must be a
pointer to a signed or unsigned integral value.
If the argument type is not usable with the conversion specificator,
the program is terminated through a call to assert() describing the
problematic format string.
The most likely problem may be that for the "%s" and "%S" formats
with a pointer argument, the type of the pointer argument is
respected. With C printf(), the actual type of the pointer argument
is ignored, and the format string determines whether it is
interpreted as a char* or a wchar_t*. Xprintf interprets the
argument diffently based on whether it is passed a char*, a
wchar_t*, a char16_t* or a char32_t*.
Xprintf does not support the Posix flag ', which means to format
using thousands separators. With C++, this is dependent on the
locale used and can not be switched on or off case by case.
With the %s format, the handling of precision and width in format
specifiers differs from that by C printf(). The C printf() function
counts bytes. This means, blanks are added for a specified width
until the specified number of bytes is reached. If the string
contains multibyte characters, and is then printed in a fixed-size
font, that can result in misaligned output. Xprintf pads to the
specified width of the Unicode string.
Even worse, if a precision is specified, the C printf() function
chops at the specified number of bytes, whithout regard to multibyte
character bounds. Xprintf truncates to the specified number of
Unicode characters if the argument is one of the C++ string types
like std::string or std::wstring. An exception is output from C
style null-terminated string pointers (char*, wchar_t* etc.):
Since these are possibly used to output from raw memory, the
precision is here interpreted as the specified number of source
characters.
Format declarators %d and %u are interpreted by xprintf() in
the identical way. The type of the argument is not converted to
signed or unsigned type. If the argument is a floating point
number, the floating point number is formatted in integral format.
In each case, the value of the argument, whether signed or unsigned,
is preserved and correctly represented in the output.
::.Copyright (c) 2014 Ruediger Helsch; All rights reserved
Permission to use, copy, modify, and distribute this software for any
purpose and without fee is hereby granted. The author disclaims all
warranties with regard to this software.