C Variadic Macro 简化对 fprintf 的调用

C Variadic Macro to simplify calls to fprintf

我定义了一个笨拙的宏,以降低自己在具有大量独特日志记录情况的项目中出错的可能性...

#define BANG(...) {fprintf(stderr, "in %s(), ", __func__);\
                   fprintf(stderr, ##__VA_ARGS__);}

而且我可以像这样调用它...

BANG("Something went wrong\n");        

但以下(显然)以可怕的方式中断...

if(emulatorExitCode == 1)
    BANG("emulatorExitCode: %d (an error)\n", emulatorExitCode);        
else
    everythingIsWonderful = 1;

我当然知道原因,这是我在调用 BANG() 时不小心留下的分号;

那个流氓分号导致 if/else 构造分成两个片段,彼此分离。这是编译器错误...

main.c:74:3: error: ‘else’ without a previous ‘if’

到目前为止一切顺利,解决方法是在我的编译器参数中包含 -Wall -Werror -Wextra -Wpedantic,这样我就不会意外地导致我的逻辑混乱。

只要我始终在 BANG() 宏调用末尾省略分号就可以了,因为宏定义在两个 fprintf(); 调用周围使用了大括号。但是我担心后面维护我的代码的其他人不会意识到这是一个问题(真的不明显)而陷入混乱。

问题

是否可以重写此宏 #define 以减少有问题的分号带来的危险 或者 是否可以重写以将对 fprintf 的这两个调用合并为一个称呼?后者是复杂的,因为它是可变的并且有著名的令人头疼的 printf-family 语义来处理。

多语句应包含在 do..while 块中以避免此类问题。

#define BANG(...) do{ \
                     fprintf(stderr, "in %s(), ", __func__);\
                     fprintf(stderr, ##__VA_ARGS__);\
                  } while (0)

因此您的 if 块将扩展为:

if(emulatorExitCode == 1)
    do{
      fprintf(stderr, "in %s(), ", __func__);   // ignoring the __func__ expansion
      fprintf(stderr, "emulatorExitCode: %d (an error)\n", emulatorExitCode);
    } while (0);
else
    everythingIsWonderful = 1;

在这种情况下,您使用可变参数宏这一事实并不重要。