Gotta tell you folks, I’m a C++ coder that uses printf-like functions. Jokes apart, there are some
serious holy wars involving the use of those format functions in C++, functions like
std::sscanf() and similar C functions that take a variable amount of parameters.
Sure C++ has its
<< >> stream operators that can do the same job
in a way nobody can easily read,
but I just think that nothing beats the simplicity and clarity of a
I mean, there is no way you can’t read that, even if you come from a language that lets you concatenate strings
+ operator. Now compare that to an
Actually, that example doesn’t look that bad in the
Now how about printing a simple hexadecimal number? Things start to get worse for Mister
The main problem with these variadic or “format” functions, however, is that they make it super easy for you to shoot yourself in the foot.
I’ll always remember a day when a friend asked me for help on how to parse a string read from a file.
I suggested that he used
std::sscanf(). He did, only he was new to these functions (coming from C# to C++)
and tried to pass an
std::string object to the function. The compiler accepted that happily, but of course,
the state of the program was corrupted after the
sscanf call returned. Variadic functions, being inherited from C,
can only deal with native types. They don’t understand the concept of C++ objects and would try to treat them as raw bytes.
There are several replacements for the old C format functions these days, Boost provides a fantastic Formating Library. With C++11, we can now implement safer templated printf-like functions that accept any data type and are type-safe.
But way before Boost and C++11 there was a way to avoid errors like the one I’ve described above.
GCC has the
__attribute__((format)) extension. Clang on OSX also fully supports it.
So if you declare your format functions as:
And try do do something silly like passing a C++ string to it, the compiler will pull your years:
Yey! The compiler is doing its job! You will be able to get some sleep tonight.
This also produces a warning if you pass types that are incompatible with the format flag
in the string, such as mismatching
__attribute__((format)) can be used with any type of function, including class methods.
But there is one little detail when using it in a class. A class method has an implicit first parameter,
this pointer. So you need to increment the
format() by one:
In fact, this is such a basic feature that even Microsoft has finally added it to
Visual Studio with the
A slightly weird syntax, but does the job.
So if you love variadic function like I do, then do yourself a favor and use these source annotations/attributes and let the compiler do the validation for you (and don’t ignore the warnings when you get them, obviously!).