09-变参宏_...和_ _VA_ARGS_ _
16.3.3 变参宏: ... 和 _ _VA_ARGS_ _
一些函数(如 printf() )接受数量可变的参数。 stdvar.h 头文件(本章后面介绍)提供了工具,让用户自定义带可变参数的函数。C99/C11也对宏提供了这样的工具。虽然标准中未使用“可变”(variadic)这个词,但是它已成为描述这种工具的通用词(虽然,C标准的索引添加了字符串化(stringizing)词条,但是,标准并未把固定参数的函数或宏称为固定函数和不变宏)。
通过把宏参数列表中最后的参数写成省略号(即,3个点 ... )来实现这一功能。这样,预定义宏
_ _VA_ARGS_ _ 可用在替换部分中,表明省略号代表什么。例如,下面的定义:
#define PR(...) printf(_ _VA_ARGS_ _)
假设稍后调用该宏:
PR("Howdy");
PR("weight = %d, shipping = $%.2f\n", wt, sp);
对于第1次调用, _ _VA_ARGS_ _ 展开为1个参数: "Howdy" 。
对于第2次调用, _ _VA_ARGS_ _ 展开为3个参数: "weight = %d, shipping = $%.2f\n" 、 wt 、 sp 。
因此,展开后的代码是:
printf("Howdy");
printf("weight = %d, shipping = $%.2f\n", wt, sp);
程序清单16.5演示了一个示例,该程序使用了字符串的串联功能和#运算符。
程序清单16.5 variadic.c 程序
// variadic.c -- 变参宏
#include <stdio.h>
#include <math.h>
#define PR(X, ...) printf("Message " #X ": " _ _VA_ARGS_ _)
int main(void)
{
double x = 48;
double y;
y = sqrt(x);
PR(1, "x = %g\n", x);
PR(2, "x = %.2f, y = %.4f\n", x, y);
return 0;
}
第1个宏调用, X 的值是 1 ,所以 #X 变成 "1" 。展开后成为:
printf("Message " "1" ": " "x = %g\n", x);
然后,串联4个字符,把调用简化为:
printf("Message 1: x = %g\n", x);
下面是该程序的输出:
Message 1: x = 48
Message 2: x = 48.00, y = 6.9282
记住,省略号只能代替最后的宏参数:
#define WRONG(X, ..., Y) #X #_ _VA_ARGS_ _ #y //不能这样做