Variadic Macros

来源:互联网 发布:淘宝上化妆品是真的吗 编辑:程序博客网 时间:2024/05/17 08:08

Variadic Macros

A macro can be declared to accept a variable number of arguments much asa function can. The syntax for defining the macro is similar to that ofa 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 (thismacro has none), including any commas, become the variableargument. This sequence of tokens replaces the identifier__VA_ARGS__ in the macro body wherever it appears. Thus, wehave 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 insertedinto the macro expansion, just like an ordinary argument. You may usethe ‘#’ and ‘##’ operators to stringify the variable argumentor to paste its leading or trailing token with another token. (But seebelow for an important special case for ‘##’.)

If your macro is complicated, you may want a more descriptive name forthe variable argument than __VA_ARGS__. CPP permitsthis, as an extension. You may write an argument name immediatelybefore 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 thisextension in the same macro.

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

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

This formulation looks more descriptive, but unfortunately it is lessflexible: you must now supply at least one argument after the formatstring. In standard C, you cannot omit the comma separating the namedargument from the variable arguments. Furthermore, if you leave thevariable argument empty, you will get a syntax error, becausethere 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 whenplaced 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 isused, then the comma before the ‘##’ will be deleted. This doesnot happen if you pass an empty argument, nor does it happen ifthe 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 macroparameter is a variable arguments parameter, as it is meaningless totry to distinguish whether no argument at all is an empty argument ora missing argument. In this case the C99 standard is clear that thecomma must remain, however the existing GCC extension used to swallowthe comma. So CPP retains the comma when conforming to a specific Cstandard, and drops it otherwise.

C99 mandates that the only place the identifier __VA_ARGS__can appear is in the replacement list of a variadic macro. It may notbe used as a macro name, macro argument name, or within a different typeof macro. It may also be forbidden in open text; the standard isambiguous. We recommend you avoid using it except for its definedpurpose.

Variadic macros are a new feature in C99. GNU CPP has supported themfor a long time, but only with a named variable argument(‘args...’, not ‘...’ and __VA_ARGS__). If you areconcerned with portability to previous versions of GCC, you should useonly named variable arguments. On the other hand, if you are concernedwith portability to other conforming implementations of C99, you shoulduse only __VA_ARGS__.

Previous versions of CPP implemented the comma-deletion extensionmuch more generally. We have restricted it in this release to minimizethe differences from C99. To get the same effect with both this andprevious versions of GCC, the token preceding the special ‘##’ mustbe a comma, and there must be white space between that comma andwhatever comes immediately before it:

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

See Differences from previous versions, for the gory details.


0 0
原创粉丝点击