【问题标题】:C Variadic Macro to simplify calls to fprintf [duplicate]C可变参数宏以简化对fprintf的调用[重复]
【发布时间】:2017-11-08 00:34:31
【问题描述】:

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

#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 语义要处理。

【问题讨论】:

标签: c coding-style c-preprocessor idioms variadic-macros


【解决方案1】:

应将多语句包装在 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;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多