Home > other >  wrapping a C printf() call in a preprocessor directive
wrapping a C printf() call in a preprocessor directive

Time:10-30

I am attempting to port C code from one platform to another and remove dependencies.

There is a debug function called dbg_out which prints out like printf().

The prototype is void dbg_out(int dbgMask, const char *pFormat, ...);

Here is an example call : dbg_out((5, "SerialDriver : (x-lx) \n", id, sn));

I would like to map this function to a normal printf() call but having some issues.

I have attempted this so far

void dbg_out (int dbgMask, const char *pFormat, ...)
__attribute__((format(printf, 2, 3)))
;    

I need to ignore the first parameter dbgMask and just take into consideration the other parameters.

I would prefer to use the preprocessor to define a wrapper. I'd appreciate some help with this.

CodePudding user response:

You need use vprintf instead, to be able to use unknown arguments

inline void dbg_out (int dbgMask, const char *pFormat, ...) {
  va_list ptr;
  va_start(ptr, pFormat);
  vprintf(pFormat, ptr);
  va_end(ptr);
}

CodePudding user response:

Using a macro

If you want to use a macro that changes the call to dbg_out to a direct call to printf, you can use a variadic macro:

#define dbg_out(mask, ...) printf(__VA_ARGS__)

int main() {
  dbg_out(1, "%d", 12);
}

if they get called like in your question with double parentheses (e.g. dbg_out((5, "%d", 12)); ), then you need to unwrap it first:

#define EXPAND(mask, ...) (__VA_ARGS__)
#define dbg_out(...) printf EXPAND __VA_ARGS__

int main() {
  dbg_out((1, "%d", 12));
}

Additionally if you know that the format is always a string literal, you could additionally add the mask to the printf output, e.g.:

#define dbg_out(mask, format, ...) printf("[Mask:%d]" format, mask, ##__VA_ARGS__)

int main() {
  dbg_out(1, "%d", 12);
}

with double parenthesis calls:

#define EXPAND(mask, format, ...) ("[Mask:%d]" format, mask, ##__VA_ARGS__)
#define dbg_out(...) printf EXPAND __VA_ARGS__ 

int main() {
  dbg_out((1, "%d", 12));
}

Redirect to another function with a macro

In case you can't change the implementation of dbg_out, you can use a macro to redirect the call to another function that does the work:

#include <stdarg.h>

#define dbg_out(...) dbg_out_new(__VA_ARGS__) 

void dbg_out_new(int mask, const char* fmt, ...) __attribute__((format(printf, 2, 3)));
void dbg_out_new(int mask, const char* fmt, ...) {
  va_list va;
  va_start(va, fmt);
  vprintf(fmt, va);
  va_end(va);
}

int main() {
    dbg_out(1, "%d", 12);
}

If it's called with double parenthesis, you need to change the macro to:

#define dbg_out(...) dbg_out_new __VA_ARGS__

/* ... */

int main() {
    dbg_out((1, "%d", 12));
}

With the __attribute__(format()) you also get the benefit of compile-time type checking of the arguments, like in the "Using a macro" example.

Change the function

In case you can edit the dbg_out function implementation, you could replace it with the above dbg_out_new implementation.

However this will not work if it gets called with double parenthesis like you wrote in your question.

  • Related