printf
is a function used to print formatted string with parameters into the console.
It comes with C standard library and has its drawbacks:
-
type information loss leads to inconsistency of types in the format string and the arguments,
-
there is no way to add a custom type, and
-
vulnerable to attacks.
Due to these reasons C++ offers iostreams
:
-
no loss of type information,
-
easy to extend overloading the stream operator, and
-
doesn’t play nasty games with the stack.
Though, printf
has very nice syntax in contrast of awkward and verbose iomanip
thingy things.
This is a proof-of-concept that type-safe printf
can be implemented.
It works with GCC 8; other compilers might not be supported, and I welcome you to contribute.
tsprintf
gives you:
-
a drop-in replacement (with limited support) of
printf
, and -
a user defined literal to call printf.
Simply call:
using namespace tsprintf;
tsprint("integer is %d\n"_lit, 42);
If it gets printed you are safe.
Note, _lit
is required.
Check out these examples of potential problems checked in compile-time:
-
few and extra arguments,
tsprint("integer is %d\n"_lit, 42, 42); // extra arguments
tsprint("integer is %d\n"_lit); // too few arguments
-
type mismatch,
tsprint("integer is %d\n"_lit, 42.0);
-
and unsecure use of dynamic format strings. The specialization of
tsprintf
taking achar const *
is marked as depricated so the compiler will warn you:
// warning: 'constexpr void tsprintf::tsprint(Fmt&&, Args&& ...)
// [with Fmt = const char*&; Args = {int&}]' is deprecated:
// can't validate a dynamic format string [-Wdeprecated-declarations]
char const *fmt = "integer is %d\n";
tsprint(fmt, 42);
-
GCC 8 or above; other compilers not tested
Note
|
GCC 8 shows deprecation warnings twice. |
On macOS run:
$ brew install gcc
$ git clone https://github.com/deni64k/tsprintf tsprintf && cd $_
$ make CXX=g++-8
It compiles and runs the example in main.cxx
.
Tip
|
Take a look at the compiler output and play with the example. |
It shows that type-safety can be implemented around formatting string literals. It can find an application in:
-
manipulating/rewriting the format string to allow Python’s
{}
-analog or fix problems casting arguments to proper types, -
adaptors for query languages such as SQL,
-
you name it.