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

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

void printf(const char* format, …);

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

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

#define debug(…) printf(__VA_ARGS__)

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

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

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

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

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

debug(“test”); //一个参数

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

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

gcc的预处理提供的可变参数宏定义真是好用:

#ifdef DEBUG
#define dbgprint(format,args...) \
fprintf(stderr, format, ##args)
#else
#define dbgprint(format,args...)
#endif

如此定义之后,代码中就可以用dbgprint了,例如dbgprint("aaa %s", __FILE__);。感觉这个功能比较Cool  :em11:

下面是C99的方法:

#define dgbmsg(fmt,...) \
             printf(fmt,__VA_ARGS__)

新的C99规范支持了可变参数的宏

具体使用如下:

以下内容为程序代码:

#include <stdarg.h> #include <stdio.h>

#define LOGSTRINGS(fm, ...) printf(fm,__VA_ARGS__)

int main() {      LOGSTRINGS("hello, %d ", 10);      return 0; }

但现在似乎只有gcc才支持。

可变参数的宏里的‘##’操作说明

带有可变参数的宏(Macros with a Variable Number of Arguments)

在1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)

这里,‘…’指可变参数。这类宏在被调用时,它(这里指‘…’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。更多的信息可以参考CPP手册。

GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:

#define debug(format, args...) fprintf (stderr, format, args)

这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。

GNU CPP还有两种更复杂的宏扩展,支持上面两种格式的定义格式。

在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:

debug ("A message")

GNU CPP在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的‘##’操作。书写格式为:

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

这里,如果可变参数被忽略或为空,‘##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。

可变参数宏__VA_ARGS__的更多相关文章

  1. 可变参数宏__VA_ARGS__和...

    __VA_ARGS__ 是一个可变参数的宏(gcc支持).实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点).这样预定义宏_ _VA_ARGS_ _就可以被用在替换部分中,替换省略号所 ...

  2. [转载]用可变参数宏(variadic macros)传递可变参数表

    注意:_VA_ARGS__ 从VS2005才开始支持 在 GNU C 中,宏可以接受可变数目的参数,就象函数一样,例如: #define pr_debug(fmt,arg...) printk(KER ...

  3. GNU C和C99标准中的可变参数宏(variadic macros)

    用可变参数宏(variadic macros)传递可变参数表你可能很熟悉在函数中使用可变参数表,如: void printf(const char* format, …); 直到最近,可变参数表还是只 ...

  4. 字符串化#、拼接字符##和可变参数宏(...和_ _VA_ARGS_ _)

    宏定义的使用与注意事项 ##是一个连接符号,用于把参数连在一起 #是“字符串化”的意思.出现在宏定义中的#是把跟在后面的参数转换成一个字符串#define paster( n ) printf( &q ...

  5. 嵌入式C语言自我修养 12:有一种宏,叫可变参数宏

    12.1 什么是可变参数宏 在上面的教程中,我们学会了变参函数的定义和使用,基本套路就是使用 va_list.va_start.va_end 等宏,去解析那些可变参数列表我们找到这些参数的存储地址后, ...

  6. c语言中的# ## 可变参数宏 ...和_ _VA_ARGS_ _

    1.#假如希望在字符串中包含宏参数,ANSI C允许这样作,在类函数宏的替换部分,#符号用作一个预处理运算符,它可以把语言符号转化程字符串.例如,如果x是一个宏参量,那么#x可以把参数名转化成相应的字 ...

  7. keil中使用——变参数宏__VA_ARGS__

    本文说的__VA_ARGS__,就是一个可变参数宏,与printf中可变参数的宏定义一个道理,是新C99规范中增加的. __VA_ARGS__详情内容 1.关于__VA_ARGS__ __VA_ARG ...

  8. CCS5 编译器手动设置dsp支持可变参数宏等问题

    IDE:CSS5.4,compiler不支持可变参数宏.需要手动设置编译器相关选项: Language Option->Language Mode —>no strict ANSI. 1. ...

  9. __VA_ARGS__可变参数宏

    #define qWiFiDebug(format, ...) qDebug("[WiFi] "format" File:%s, Line:%d, Function:%s ...

随机推荐

  1. 前端html、Javascript、CSS技术小结

    简单地总结了一下前端用过的html.javascript.css技术,算是清点一下,做个大略的小结,为进一步的学习给个纲领. 一.HTML 由于HTML5的兴起,简单地判断一个网页是否是html5网页 ...

  2. 用户图形界面(GUI)学习笔记(一)——Swing与AWT

    一.Swing与AWT 对象窗口工具箱(Abstact Window Toolkit,AWT),是JAVA1.0刚出现的时候,包含的一个GUI设计类库.它将处理用户界面元素的任务委派给每个目标平台(W ...

  3. ios的网络数据下载和json解析

    ios的网络数据下载和json解析 简介 在本文中,笔者将要给大家介绍如何使用nsurlconnection 从网上下载数据,以及解析json数据格式,以及如何显示数据和图片的异步下载显示. 涉及的知 ...

  4. 循环处理--sqlserver

    alter PROCEDURE [dbo].[sp_gongzi] @gongzi_yf varchar(7) as DECLARE  @input_id varchar(20)DECLARE  @s ...

  5. MVC+EF6使用MySQL+CodeFirst的详细配置

    环境: WIN7(64位旗舰版)+VS2012+MySQL5.6(32位版,在另一台服务器中,环境是win2003) 1.下载并安装MysqlforVisualStudio.zip,此软件功能是让VS ...

  6. [.NET领域驱动设计实战系列]专题九:DDD案例:网上书店AOP和站点地图的实现

    一.引言 在前面一专题介绍到,要让缓存生效还需要实现对AOP(面向切面编程)的支持.所以本专题将介绍了网上书店案例中AOP的实现.关于AOP的概念,大家可以参考文章:http://www.cnblog ...

  7. 可在广域网部署运行的QQ高仿版 -- GG叽叽V2.4,增加远程协助、桌面共享功能(源码)

    QQ的远程协助.或者说桌面共享是一个非常实用的功能,所以,2.4版本的GG复制了它,而且,GG增强了桌面共享的功能,它可以允许指定要共享桌面的区域,这样,对方就只能看到指定区域的桌面,这对节省流量会非 ...

  8. 算法:poj1066 宝藏猎人问题。

    package practice; import java.util.Scanner; public class TreasureHunt { public static void main(Stri ...

  9. 作业三(代码规范、代码复审、PSP)

    1.代码规范: 我支持代码要有规范,理由如下. (1).艺术是一个很带有个人风格的学科,天马行空才能凸显出自己的价值.但不要忘了,会艺术的不是生下来就会艺术, 他也需要按照前辈的步骤一步一步的学习基础 ...

  10. prerender-SPA程序的SEO优化策略

    随着web2.0的兴起,ajax的时代已经成为了事实,更如今Knockout,backbone, angular,ember前端MDV(model driver view)框架强势而来,Single ...