C 为printf使用_VA_参数

C 为printf使用_VA_参数,c,printf,c-preprocessor,C,Printf,C Preprocessor,我正在尝试使用\u VA_ARGS为ASSERT()编写\define。 (此代码适用于不支持所有libc函数的嵌入式处理器) 我的源代码如下: ASSERT(msg == NULL) 头文件中的断言: #define ASSERT(...) if(__VA_ARGS__) { printf("[ASSERT ERROR]" __VA_ARGS__ "\n"); } 预处理器的输出如下,这导致编译错误 if(msg == NULL) { printf("[ASSERT ERROR]" msg

我正在尝试使用
\u VA_ARGS
ASSERT()
编写
\define

(此代码适用于不支持所有libc函数的嵌入式处理器)

我的源代码如下:

ASSERT(msg == NULL)
头文件中的断言:

#define ASSERT(...) if(__VA_ARGS__) { printf("[ASSERT ERROR]" __VA_ARGS__ "\n"); }
预处理器的输出如下,这导致编译错误

if(msg == NULL) { printf("[ASSERT ERROR]" msg == NULL "\n"); }

如何修复
#define
,在保持代码逻辑正确的同时消除编译错误?

没有理由认为这是一个可变宏,至少不需要告诉我们有关您正试图执行的操作的更多信息。使用字符串化操作符
#
的简单单参数宏可以很好地完成以下任务:

#define ASSERT(x) if(x); else printf("[ASSERT ERROR] " #x "\n")
还要注意,我省略了结尾处的分号,并将其写成
if(x);else
而不是
if(!(x))
,以便以下所有代码片段按照预期正确编译,或者按照预期生成编译器错误:

// #1 - this must be an error, no semicolon
ASSERT(x)

// #2 - this must also be an error
ASSERT(x)
else
    /*stuff*/ ;

// #3 - the else must go with the first if, not the inner if inside the macro
// expansion
if (x)
    ASSERT(y);
else
    /*stuff*/ ;

您的原始宏定义未通过上述测试#3。

没有理由将其视为可变宏,至少不能告诉我们有关您正试图执行的操作的更多信息。使用字符串化操作符
#
的简单单参数宏可以很好地完成以下任务:

#define ASSERT(x) if(x); else printf("[ASSERT ERROR] " #x "\n")
还要注意,我省略了结尾处的分号,并将其写成
if(x);else
而不是
if(!(x))
,以便以下所有代码片段按照预期正确编译,或者按照预期生成编译器错误:

// #1 - this must be an error, no semicolon
ASSERT(x)

// #2 - this must also be an error
ASSERT(x)
else
    /*stuff*/ ;

// #3 - the else must go with the first if, not the inner if inside the macro
// expansion
if (x)
    ASSERT(y);
else
    /*stuff*/ ;

您的原始宏定义未通过上面的测试#3。

宏的意义是什么?宏的意义是什么?+1,但某些编译器仍会在
if(to)ASSERT(x)上发出虚假的
else
警告。对于这种情况,封装在良好的旧
do{..}while(false)
规则中。而且没有理由不使用
\uu VA\u ARGS\uu
执行宏。有人可能想给它传递一个逗号表达式:)@Jens:没错,有些编译器可能会很挑剔。如果没有必要,可以避免使用
\uu VA\u ARGS\uu
,原因之一是它是C99功能,因此不能将它与不支持它作为扩展的C89编译器一起使用。如果您确实想传递逗号表达式,可以在非变量宏中添加一组额外的括号,例如
ASSERT((foo,bar))
@Adam Rosenfield谢谢您的建议。在我的代码中我有
ASSERT(x)
,我的定义是
#define ASSERT(x)if(x){}else{printf(“[ASSERT BUG]”x“\n”)
并且它成功编译。@SudharsanSeshadri:您必须删除该宏中调用
printf
时的大括号和分号,否则它可能导致代码编译成功,但却默默地做了错误的事情——这正是我上面示例中的第3种情况。宏很难正确执行(因此).1,但不幸的是,一些编译器仍然会在
if(to)ASSERT(x);
上发出虚假的
else
警告。对于封装在良好的旧
中的这种情况,请执行{..}while(false)
仍然是规则。而且也没有理由不使用
\uuuu VA\u ARGS\uuuu
来执行宏。可能有人想给它传递一个逗号表达式:)@Jens:True,有些编译器可能会很挑剔。避免使用
\uu VA\u ARGS\uuuu
的一个原因是它是C99功能,因此不能与不支持如果你真的想传递一个逗号表达式,你可以在非变量宏中添加一组额外的括号,例如
ASSERT((foo,bar))
@Adam Rosenfield谢谢你的建议。在我的代码中我有
ASSERT(x)
,我的定义是
\define ASSERT(x)If(x){}else{printf([ASSERT BUG]“\x”\n)
并且它编译成功。@SudharsanSeshadri:您必须删除该宏中对
printf
的调用周围的大括号和分号,否则它可能导致代码编译成功,但却默默地做了错误的事情——在我上面的示例中正好是第3种情况。宏很难做到正确(这就是为什么)。