可变参数宏__VA_ARGS__

在 GNU C 中,宏可以接受可变数目的参数,就象函数一样,例如:
#define pr_debug(fmt,arg...) \
printk(KERN_DEBUG fmt,##arg)



用可变参数宏(variadicmacros)传递可变参数表
你可能很熟悉在函数中使用可变参数表,如:

void printf(const char* format,…);

直到最近,可变参数表还是只能应用在真正的函数中,不能使用在宏中。

C99编译器标准终于改变了这种局面,它允许你可以定义可变参数宏(variadicmacros),这样你就可以使用拥有可以变化的参数表的宏。可变参数宏就像下面这个样子:

#define debug(…)printf(__VA_ARGS__)

缺省号代表一个可以变化的参数表。使用保留名 __VA_ARGS__把参数传递给宏。当宏的调用展开时,实际的参数就传递给<wbr><em>printf()</em>了。例如:</wbr>

Debug(“Y = %d\n”, y);

而处理器会把宏的调用替换成:

printf(“Y = %d\n”, y);

因为debug()是一个可变参数宏,你能在每一次调用中传递不同数目的参数:

debug(“test”);<wbr><span style="color:#006600">//一个参数</span></wbr>

可变参数宏不被ANSI/ISO C++ 所正式支持。因此,你应当检查你的编译器,看它是否支持这项技术。


用GCC和C99的可变参数宏,更方便地打印调试信息


gcc的预处理提供的可变参数宏定义真是好用:<wbr><br style="font:normal normal normal 12px/normal song,Verdana"></wbr>
#ifdef<wbr>DEBUG<br style="font:normal normal normal 12px/normal song,Verdana">
   #define<wbr>dbgprint(format,args...)<wbr>\<br style="font:normal normal normal 12px/normal song,Verdana">
 fprintf(stderr,<wbr>format,<wbr>##args)<br style="font:normal normal normal 12px/normal song,Verdana">
#else<br style="font:normal normal normal 12px/normal song,Verdana">
    #define<wbr>dbgprint(format,args...)<br style="font:normal normal normal 12px/normal song,Verdana">
#endif<br style="font:normal normal normal 12px/normal song,Verdana"></wbr></wbr></wbr></wbr></wbr></wbr>
如此定义之后,代码中就可以用dbgprint了,例如dbgprint("aaa
<wbr>%s",<wbr>__FILE__);。感觉这个功能比较Cool<wbr><wbr>:em11:<wbr><br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"> 下面是C99的方法:<wbr><br style="font:normal normal normal 12px/normal song,Verdana"><pre>#define<wbr>dgbmsg(fmt,...)<wbr>\<br style="font:normal normal normal 12px/normal song,Verdana"><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> printf(fmt,__VA_ARGS__)<br style="font:normal normal normal 12px/normal song,Verdana"></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></pre> <br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"><p style="font:normal normal normal 12px/normal song,Verdana">新的C99规范支持了可变参数的宏</p> <p style="font:normal normal normal 12px/normal song,Verdana">具体使用如下:</p> <p style="font:normal normal normal 12px/normal song,Verdana"><wbr>以下内容为程序代码:</wbr></p> <p style="font:normal normal normal 12px/normal song,Verdana"><wbr>#include&lt;stdarg.h&gt;<wbr>#include&lt;stdio.h&gt;</wbr></wbr></p> <p style="font:normal normal normal 12px/normal song,Verdana"><wbr>#define LOGSTRINGS(fm, ...)printf(fm,__VA_ARGS__)</wbr></p> <p style="font:normal normal normal 12px/normal song,Verdana"><wbr>intmain()<wbr>{<wbr><wbr><wbr><wbr><wbr>LOGSTRINGS("hello, %d ",10);<wbr><wbr><wbr><wbr><wbr>return 0;<wbr>}<wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p style="font:normal normal normal 12px/normal song,Verdana"><wbr>但现在似乎只有gcc才支持。</wbr></p> <br style="font:normal normal normal 12px/normal song,Verdana"><h1>可变参数的宏里的‘##’操作说明</h1> <br style="font:normal normal normal 12px/normal song,Verdana"><span style="font-family:宋体">带有可变参数的宏(</span><span lang="EN-US">Macros with a Variable Number ofArguments</span><span style="font-family:宋体">)</span> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span style="font-family:宋体">在</span><span lang="EN-US">1999</span><span style="font-family:宋体">年版本的</span><span lang="EN-US">ISOC<wbr></wbr></span><span style="font-family:宋体">标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:</span></p> <p align="left" style="font:normal normal normal 12px/normal song,Verdana; text-align:left"> <span lang="EN-US" style="font-family:CMTT9; font-size:9pt">#define debug(format, ...)fprintf (stderr, format, __VA_ARGS__)</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span style="font-family:宋体">这里,‘</span><span lang="EN-US">…</span><span style="font-family:宋体">’指可变参数。这类宏在被调用时,它(这里指‘</span><span lang="EN-US">…</span><span style="font-family:宋体">’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(</span><span lang="EN-US">macrobody</span><span style="font-family:宋体">)中,那些符号序列集合将代替里面的</span><span lang="EN-US">__VA_ARGS__</span><span style="font-family:宋体">标识符。更多的信息可以参考</span><span lang="EN-US">CPP</span><span style="font-family:宋体">手册。</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span lang="EN-US">GCC</span><span style="font-family:宋体">始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:</span></p> <p style="font:normal normal normal 12px/normal song,Verdana"><span lang="EN-US">#define debug(format, args...) fprintf (stderr, format,args)</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span style="font-family:宋体">这和上面举的那个</span><span lang="EN-US">ISO C</span><span style="font-family:宋体">定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span lang="EN-US">GNU CPP</span><span style="font-family:宋体">还有两种更复杂的宏扩展,支持上面两种格式的定义格式。</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span style="font-family:宋体">在标准</span><span lang="EN-US">C</span><span style="font-family:宋体">里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在</span><span lang="EN-US">ISOC</span><span style="font-family:宋体">里是非法的,因为字符串后面没有逗号:</span></p> <p style="font:normal normal normal 12px/normal song,Verdana"><span lang="EN-US">debug ("A message")</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span lang="EN-US">GNU CPP</span><span style="font-family:宋体">在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(</span><span lang="EN-US">complain</span><span style="font-family:宋体">),因为宏展开后,里面的字符串后面会有个多余的逗号。</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span style="font-family:宋体">为了解决这个问题,</span><span lang="EN-US">CPP</span><span style="font-family:宋体">使用一个特殊的‘</span><span lang="EN-US">##</span><span style="font-family:宋体">’操作。书写格式为:</span></p> <p style="font:normal normal normal 12px/normal song,Verdana"><span lang="EN-US">#define debug(format, ...) fprintf (stderr, format, ##__VA_ARGS__)</span></p> <p style="font:normal normal normal 12px/normal song,Verdana; text-indent:21pt"><span style="font-family:宋体">这里,如果可变参数被忽略或为空,‘</span><span lang="EN-US">##</span><span style="font-family:宋体">’操作将使预处理器(</span><span lang="EN-US">preprocessor</span><span style="font-family:宋体">)去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,</span><span lang="EN-US">GNUCPP</span><span style="font-family:宋体">也会工作正常,它会把这些可变参数放到逗号的后面。象其它的</span><span lang="EN-US">pasted macro</span><span style="font-family:宋体">参数一样,这些参数不是宏的扩展。<br style="font:normal normal normal 12px/normal song,Verdana"></span></p> <span style="font-family:宋体"><br style="font:normal normal normal 12px/normal song,Verdana"></span><br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"><h1>怎样写参数个数可变的宏</h1> <br style="font:normal normal normal 12px/normal song,Verdana"> 一种流行的技巧是用一个单独的用括弧括起来的的<wbr>``参数"<wbr>定义和调用宏,参数在宏扩展的时候成为类似<wbr>printf()<wbr>那样的函数的整个参数列表。 <pre> #define DEBUG(args) (printf("DEBUG: "), printf args)<br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"> if(n != 0) DEBUG(("n is %d\n", n));<br style="font:normal normal normal 12px/normal song,Verdana"></pre> <p style="font:normal normal normal 12px/normal song,Verdana">明显的缺陷是调用者必须记住使用一对额外的括弧。</p> <p style="font:normal normal normal 12px/normal song,Verdana">gcc<wbr>有一个扩展可以让函数式的宏接受可变个数的参数。 但这不是标准。另一种可能的解决方案是根据参数个数使用多个宏<wbr>(DEBUG1, DEBUG2, 等等), 或者用逗号玩个这样的花招:</wbr></wbr></p> <pre> #define DEBUG(args) (printf("DEBUG: "), printf(args))<br style="font:normal normal normal 12px/normal song,Verdana"> #define _ ,<br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"> DEBUG("i = %d" _ i);<br style="font:normal normal normal 12px/normal song,Verdana"></pre> <p style="font:normal normal normal 12px/normal song,Verdana">C99<wbr>引入了对参数个数可变的函数式宏的正式支持。在宏<wbr>``原型"<wbr>的末尾加上符号<wbr>...(就像在参数可变的函数定义中),宏定义中的伪宏<wbr>__VA_ARGS__<wbr>就会在调用是替换成可变参数。</wbr></wbr></wbr></wbr></wbr></wbr></p> 最后, 你总是可以使用真实的函数, 接受明确定义的可变参数<br style="font:normal normal normal 12px/normal song,Verdana"><br style="font:normal normal normal 12px/normal song,Verdana"> 如果你需要替换宏, 使用一个 函数和一个非函数式宏, 如<wbr>#define printfmyprintf。</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

你可能感兴趣的:(可变参数)