3.6 Variadic Macros

A macro can be declared to accept a variable number of arguments much as a function can. The syntax for defining the macro is similar to that of a function. Here is an example:

     #define eprintf(...) fprintf (stderr, __VA_ARGS__)

This kind of macro is called variadic. When the macro is invoked, all the tokens in its argument list after the last named argument (this macro has none), including any commas, become the variable argument. This sequence of tokens replaces the identifier __VA_ARGS__ in the macro body wherever it appears. Thus, we have this expansion:

     eprintf ("%s:%d: ", input_file, lineno)
==> fprintf (stderr, "%s:%d: ", input_file, lineno)

The variable argument is completely macro-expanded before it is inserted into the macro expansion, just like an ordinary argument. You may use the ‘#’ and ‘##’ operators to stringify the variable argument or to paste its leading or trailing token with another token. (But see below for an important special case for ‘##’.)

If your macro is complicated, you may want a more descriptive name for the variable argument than __VA_ARGS__. CPP permits this, as an extension. You may write an argument name immediately before the ‘...’; that name is used for the variable argument. The eprintf macro above could be written

     #define eprintf(args...) fprintf (stderr, args)

using this extension. You cannot use __VA_ARGS__ and this extension in the same macro.

You can have named arguments as well as variable arguments in a variadic macro. We could define eprintf like this, instead:

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

This formulation looks more descriptive, but unfortunately it is less flexible: you must now supply at least one argument after the format string. In standard C, you cannot omit the comma separating the named argument from the variable arguments. Furthermore, if you leave the variable argument empty, you will get a syntax error, because there will be an extra comma after the format string.

     eprintf("success!\n", );
==> fprintf(stderr, "success!\n", );

GNU CPP has a pair of extensions which deal with this problem. First, you are allowed to leave the variable argument out entirely:

     eprintf ("success!\n")
==> fprintf(stderr, "success!\n", );

Second, the ‘##’ token paste operator has a special meaning when placed between a comma and a variable argument. If you write

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

and the variable argument is left out when the eprintf macro is used, then the comma before the ‘##’ will be deleted. This does not happen if you pass an empty argument, nor does it happen if the token preceding ‘##’ is anything other than a comma.

     eprintf ("success!\n")
==> fprintf(stderr, "success!\n");

The above explanation is ambiguous about the case where the only macro parameter is a variable arguments parameter, as it is meaningless to try to distinguish whether no argument at all is an empty argument or a missing argument. CPP retains the comma when conforming to a specific C standard. Otherwise the comma is dropped as an extension to the standard.

The C standard mandates that the only place the identifier __VA_ARGS__ can appear is in the replacement list of a variadic macro. It may not be used as a macro name, macro argument name, or within a different type of macro. It may also be forbidden in open text; the standard is ambiguous. We recommend you avoid using it except for its defined purpose.

Variadic macros became a standard part of the C language with C99. GNU CPP previously supported them with a named variable argument (‘args...’, not ‘...’ and __VA_ARGS__), which is still supported for backward compatibility.

c语言中三个点的解释 : variadic的更多相关文章

  1. 关于C语言中整数范围的一些解释

    示例代码 #include <stdio.h> int main() { ; printf("%d\n", c); ; printf("%d\n", ...

  2. C语言中最常用的三种输入输出函数scanf()、printf()、getchar()和putchar()

    本文给大家介绍C语言中最常用的三种输入输出函数scanf().printf().getchar()和putchar(). 一.scanf()函数格式化输入函数scanf()的功能是从键盘上输入数据,该 ...

  3. C语言中的三字母词

    C语言中的三字母词(trigraph) 在ANSI C标准中,定义了9个三字母词(trigraph),三字母词就是几个字符的序列,合起来表示另一个字符.三字母词使C语言环境可以在缺少一些必需字符的字符 ...

  4. C语言中的三值合一

    在学习C语言中我们会发现这样一种情况: #include<stdio.h> Int main() { Int ar[10]; printf(“%p\n”,ar); printf(“%p\n ...

  5. C语言中可变参数的函数(三个点,“...”)

    C语言中可变参数的函数(三个点,“...”) 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end ...

  6. c语言中字符串数组初始化的一点总结&& c++访问控制的三种方式

    char *c[]={"ONE","TWO","THREE","FOUR"}; // c语言中定义了一个字符串数组(也称 ...

  7. 【】VMware vSphere中三种磁盘规格的解释说明

    在VMware vSphere中,不管是以前的5.1版本,或者是现在的6.5版本,创建虚拟机时,在创建磁盘时,都会让选择磁盘的置备类型,如下图所示,分为: 厚置备延迟置零 厚置备置零 Thin Pro ...

  8. C语言中的栈和堆

    原文出处<http://blog.csdn.net/xiayufeng520/article/details/45956305#t0> 栈内存由编译器分配和释放,堆内存由程序分配和释放. ...

  9. C语言中的强符号与弱符号

    转自:http://blog.csdn.net/astrotycoon/article/details/8008629 一.概述 在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初 ...

随机推荐

  1. 【转载】Delphi7从子线程中发送消息到主线程触发事件执行

    在对数据库的操作时,有时要用一个子线程来进行后台的数据操作.比如说数据备份,转档什么的.在主窗口还能同是进行其它操作.而有时后台每处理一个数据文件,要向主窗口发送消息,让主窗口实时显示处理进度在窗口上 ...

  2. window下编译并使用google protobuf

    参考网址: http://my.oschina.net/chenleijava/blog/261263 http://www.ibm.com/developerworks/cn/linux/l-cn- ...

  3. 别人整理的DP大全(转)

    动态规划 动态规划 容易: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ...

  4. sql语句-ALTER TABLE

    在工作中常遇到要维护数据库表的列,这里主要介绍sql语句中的ALTER TABLE 语句.ALTER TABLE 语句用于在已有的表中添加.修改或删除列. 如需在表中添加列,请使用下列语法: ALTE ...

  5. CodeBlocks安装及配置注意事项

    在使用codeblocks的时候,网上一般只会提供CodeBlocks的项目文件,并不包括编译器和调试器,要使用CodeBlocks的完整功能需要在官网下载完整版. 如图可下载mingw版本. 进入C ...

  6. Android 用HorizontalScrollView实现ListView的Item滑动删除 ,滑动错乱 冲突

    用HorizontalScrollView实现类似微信的滑动删除 测试于:Android2.2+ 对于Android来说按键操作已经在减少,越来越多的手势操作层出不穷,今天介绍一款LIstView的I ...

  7. Raspberry pi(-) Mac下安装系统

    购买树莓派一般的操作说明书都是windows下的,因为本人只有MBP,外加虚拟机Parallels Desktop无法识别SD卡,所以就直接参考Mac教程了. 1.系统镜像官网下载 推荐用Raspbi ...

  8. 《JavaScript高级程序设计》学习笔记(5)——面向对象编程

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第六章内容. 1.面向对象(Object ...

  9. STL之序列式容器list与forward_list

    List (双向链表) 与 forwardlist (单向链表) 算是非常基础的数据结构了,这里只是简单介绍下其结构及应用. 以list为例: 其节点模板: template <class T& ...

  10. python celery + redis

    redis http://debugo.com/python-redis celery http://docs.jinkan.org/docs/celery/getting-started/intro ...