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;
在这种情况下,您使用可变参数宏这一事实并不重要。
我定义了一个笨拙的宏,以降低自己在具有大量独特日志记录情况的项目中出错的可能性...
#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;
在这种情况下,您使用可变参数宏这一事实并不重要。