现在的位置: 首页 > 综合 > 正文

可变参数宏 , Variadic Macros

2017年12月20日 ⁄ 综合 ⁄ 共 2308字 ⁄ 字号 评论关闭

说起可变参数,立即想到的就是printf(),scanf()了。可变参数就是有一个固定的格式控制参数,后面再根据格式控制参数接若干参数。

         这里先讨论可变参数宏。

         我们一般在Debug需要打印调试信息的时候,需要可变参数的宏。

         一, vc(C99)的复杂宏。

        
参考msdn(http://msdn2.microsoft.com/en-us/library/ms177415.aspx
)。使用这种复杂宏时,省略号是格式控制参数,而标识符__VA_ARGS__用来插入另外的参数。__VA_ARGS__ 将"..." 传递给宏。

例如:

#include <stdio.h>

#define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }
#define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); }
#define CHECK3(...) { printf(__VA_ARGS__); }

int main( )
{
        CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)/n");
        CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)/n");     // won't print
        CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)/n");     // won't print
        CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)/n");
        CHECK3("here %s %s %s", "are", "some", "varargs3(5)/n");
        return 0;
}

输出为:

here are some varargs1(1)
here are some varargs2(4)
here are some varargs3(5)

         二,GCC中的复杂宏

         GCC支持C99中的复杂宏,但G++不支持。GCC使用一种不同的语法,给可变参数一个名字,如同其它参数一样。

#define CHECK1(x,format, args...) if(x) { printf (format, args); }

         显然这样易于描述而且可读性更强。

          三,CHECK("Some messges.")的情况

         这时由于宏展开后有个多余的逗号,,将导致编译错误.。为了解决这个问题,CPP使用一个特殊的“##”操作。

        #define CHECK(format, ...) printf ( format, ## __VA_ARGS__)

       
这里,如果可变参数被忽略或为空,“##”操作将使预处理器去除掉它前面的那个逗号。如果在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。

         四,类似printf()的技巧

         用一个被括弧括起来的 “参数”来定义和调用宏,参数在宏扩展的时候成为类似printf()函数中的格式控制字符串那样的参数列表。

        
#define CHECK(args) (printf("DEBUG: "), printf(args))

        
用了括号。

/////////////////////////////////////////////////

  


今天来说说宏。什么?宏也能可变参数?是的,你没有听错,带参数的宏和函数一样,同样支持可变参数。下面通过一个小程序加以说明。

#include

#include


#define OUTSCREEN(msg, ...) printf(msg,__VA_ARGS__)


int main(int argc, char* argv[])

{

     
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");

     
return 0;

}


     


这个可变参数的宏是新的
C99

规范中新增的,目前似乎只有
gcc

支持(
VC6.0

的编译器不支持)。



#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)


int main(int argc, char* argv[])

{

     
OUTSCREEN("Hello World!n%s", "__This is a MACRO!n");

     
return 0;

}


    


假如我们将上面的代码稍作一下修改,变成下面的样子。


#define OUTSCREEN(msg, ...) printf(msg, __VA_ARGS__)


int main(int argc, char* argv[])

{

     
OUTSCREEN("Hello World!");

     
return 0;

}


    


注意我仅仅是将
main

函数里的
OUTSCREEN

做了修改,这时可变参数的个数为
0

了。但是编译的时候
gcc

却报错:

In function `main':

error: parse error before ')' token



    


什么原因导致出错呢?把宏展开一下看看,原来是
","

惹得祸。那么这种参数个数可以为
0

的宏要怎么写呢?
C99

的规范没有定义这个,
gcc

对此做了扩展。重新定义
OUTSCREEN

宏如下:

#define OUTSCREEN(msg, ...) printf(msg, ##__VA_ARGS__)


【上篇】
【下篇】

抱歉!评论已关闭.