This sounds a little like an interview question,but is actually a practical problem.
I am working with an embedded platform, and have available only the equivalents of those functions:
- printf()
- snprintf()
Furthermore, the printf() implementation (and signature) is likely to change in the near future, so calls to it have to reside in a separate module, in order to be easy to migrate later.
Given those, can I wrap logging calls in some function or macro? The goal is that my source code calls THAT_MACRO("Number of bunnies: %d", numBunnies);
in a thousand places, but calls to the above functions are seen only in one place.
Compiler: arm-gcc -std=c99
This works like this:
It defines the parameterized macro PRINTF to accept (up to) infinite arguments, then preprocesses it from
PRINTF(...)
toprintf(__VA_ARGS__)
.__VA_ARGS__
is used in parameterized macro definitions to denote the arguments given ('cause you can't name infinite arguments, can you?).There are 2 ways to do this:
Variadric macro
function that forwards
va_args
There are also
vsnprintf
,vfprintf
and whatever you can think of instdio
.Since you can use C99, I'd wrap it in a variadic macro:
since you didn't say that you have
vprintf
or something like it. If you do have something like it, you could wrap it in a function like Sergey L has provided in his answer.Edit:
The above TM_PRINTF does not work with an empty VA_ARGS list. At least in GCC it is possible to write:
The two ## signs remove remove the excess comma in front of them them if
__VA_ARGS__
is empty.Limited library? Embedded system? Need as much performance as possible? No problem!
As demonstrated in this answer to this question, you can use assembly language to wrap function which do not accept VA_LIST into ones that do, implementing your own vprintf at little cost!
While this will work, and almost certainly result in the performance as well as abstraction you want, I would just recommend you get a more feature filled standard library, perhaps by slicing parts of uClibc. Such a solution is surely to be a more portable and overall more useful answer than using assembly, unless you absolutely need every cycle.
That's why such projects exist, after all.
The
##
token will enable the usageTM_PRINTF("aaa");
If you can live with having to wrap the call in two parentheses, you can do it like this:
Then use it:
This works since from the preprocessor's point of view, the entire list of arguments becomes one macro argument, which is substituted with the parenthesis.
This is better than just plain doing
Since it allows you to define it out:
This will "eat up" the macro arguments, they will never be part of the compiled code.
UPDATE Of course in C99 this technique is obsolete, just use a variadic macro and be happy.