在预处理器指令中包装 C printf() 调用

wrapping a C printf() call in a preprocessor directive

我正在尝试将 C 代码从一个平台移植到另一个平台并删除依赖项。

有一个名为 dbg_out 的调试函数,其打印结果类似于 printf()

原型是void dbg_out(int dbgMask, const char *pFormat, ...);

这是一个调用示例:dbg_out((5, "SerialDriver : (%04x-%08lx) \n", id, sn));

我想将此函数映射到正常的 printf() 调用,但遇到了一些问题。

到目前为止我已经尝试过了

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

我需要忽略第一个参数 dbgMask,只考虑其他参数。

我更愿意使用预处理器来定义包装器。如果能提供一些帮助,我将不胜感激。

您需要改用 vprintf 才能使用未知参数

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

使用宏

如果您想使用宏将对 dbg_out 的调用更改为对 printf 的直接调用,您可以使用可变参数宏:

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

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

如果他们像您的问题中那样用双括号调用(例如 dbg_out((5, "%d", 12)); ), 那么你需要先解包:

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

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

此外,如果您知道格式始终是字符串文字,您可以另外将掩码添加到printf 输出,例如:

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

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

双括号调用:

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

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

使用宏重定向到另一个函数

如果您无法更改 dbg_out 的实现,您可以使用宏将调用重定向到另一个完成工作的函数:

#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);
}

如果用双括号调用,需要把宏改成:

#define dbg_out(...) dbg_out_new __VA_ARGS__

/* ... */

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

使用 __attribute__(format()),您还可以获得参数的编译时类型检查的好处,就像在“使用宏”示例中一样。

更改功能

如果您可以编辑 dbg_out 函数实现,则可以将其替换为上面的 dbg_out_new 实现。

但是,如果像您在问题中写的那样用双括号调用它,这将不起作用。