Name | Modified | Size | Downloads / Week |
---|---|---|---|
xprintf-0.3.1.zip | 2014-07-02 | 114.6 kB | |
xprintf-0.3.1.tar.gz | 2014-07-02 | 91.2 kB | |
README.md | 2014-07-01 | 22.8 kB | |
Totals: 3 Items | 228.6 kB | 0 |
Xprintf - printf for C++11
Contents
- Introduction
- Installation
- Usage
- xprintf(format, args...)
- Redirect default stream
- xprintf(stream, format, args...)
- sxprintf(format, args...)
- Creating a Library
- Compatibility
- Format String, Conversion Specifications
- Problems, Incompatibilities and Bugs
- StrCvt - Charcter conversion
- License
Introduction
This is an implementation of printf for C++11.
- Full standard C printf() format support, most of Posix and X/Open extensions like positional parameters, seamless integration of C++ strings.
- Full type safety, respects the type of the arguments. Argument size
specifiers like
l
are accepted but mostly ignored, since the type of the arguments is consulted for the size. - Seamless support for arbitrary combinations of narrow and wide output streams and output strings, narrow and wide format strings, narrrow and wide arguments.
- Seamless support for new
char16_t
andchar32_t
character and string types using the included StrCvt package for character type conversions.
In 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);
Installation
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"
.
Usage
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 Charcvt headers and namespaces.
xprintf(format, args...)
The most flexible way to use xprintf() is through the call
xprintf(format, args...)
. The expression xprintf(format, args...)
can be used as follows:
- It can be used as argument to
operator<<
, which writes the formatted result to the output stream. - It can be assigned to a
string
orwstring
, which receives the formatted output. - The output can be left unused. In this case it is written to the standard output (or another stream, see below).
The 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:
- The format can be a
char
or awchar_t
character string constant or astring
orwstring
. - Independently, the output stream can be a narrow or a wide character stream, and the string assigned from the result can be a narrow or a wide string.
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.
Redirect default output stream
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.
xprintf(stream, format, args...)
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().
sxprintf(format, args...)
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.
Creating a Library
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.
Compatibility
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:
- GCC 4.7, 4.8 and 4.9 on Linux
- Visual Studio Express 2013 for Windows Desktop with November 2013 CTP
- Intel C++ 14.0.2 on Linux
- Clang 3.5.0 on Linux
Format String, Conversion Specifications
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$
, withn
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$
withn
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$
withn
a decimal integer number (see below). -
An optional argument size modifier in the form
hh
,h
,l
,ll
,j
,z
,t
orL
. -
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, thespace
flag is ignored. -
#
The result is converted in an alternative form. Foro
,x
andX
conversion specifiers, the number is prefixed by0
,0x
or0X
. Forf
,F
,e
,E
,g
,G
,a
andA
conversion, the result is always formatted with a decimal point character, even if no digits follow it. Forg
andG
conversions, trailing zeros are not removed from the result. For the bool conversion specifierB
, write0
or1
instead offalse
andtrue
. 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
,u
Format 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
,X
Format 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
,F
Format 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
,E
Format 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
,G
Format 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
,A
Format 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
,C
Convert 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
,S
Format 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.
p
Format the argument in an implementation-defined pointer format. The argument must be a pointer or a signed or unsigned integral type.
B
Format 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
,M
Format 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.
n
Do 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.
Problems, Incompatibilities and Bugs
-
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 awchar_t*
. Xprintf interprets the argument diffently based on whether it is passed achar*
, awchar_t*
, achar16_t*
or achar32_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
orstd::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.
Bugs
- The standard I/O functions in header xprintf/xprintf_std.h are not
selected by the function overload resolution if only the format
string and no further arguments are specified. In this case
argument dependent lookup selects the standard functions in
namespace
::
.
License
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.