1 可变参数的函数
最初,C中只有函数支持可变参数,例如最常见的printf系列函数,其声明如下:
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int sprintf(char *str, const char *format, ...); int snprintf(char *str, size_t size, const char *format, ...);
#include <stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap); |
#include <stdarg.h> void va_start(va_list ap, last); /*功能:用可变参数前的最后一个参数last初始化ap*/ type va_arg(va_list ap, type); /*功能:返回ap后面type类型的参数*/ void va_end(va_list ap); /*功能:终止ap使用*/ void va_copy(va_list dest, va_list src);/*功能:把src拷贝给dest*/
定义: typedef char *va_list;
#define _AUPBND (sizeof (acpi_native_int) - 1) #define _ADNBND (sizeof (acpi_native_int) - 1)
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) #define va_end(ap) (ap = (va_list) NULL) #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
其中,acpi_native_int定义为typedef s32acpi_native_int;或typedef s64 acpi_native_int; |
void print(char* fmt, ...)
{
double vargflt = 0;
int vargint = 0;
char* vargpch = NULL;
char vargch = 0;
char* pfmt = NULL;
va_list vp;
va_start(vp, fmt);
pfmt = fmt;
while(*pfmt)
{
if(*pfmt == '%')
{
switch(*(++pfmt))
{
case 'c':
vargch = va_arg(vp, int);
/* va_arg(ap, type), if type is narrow type (char, short, float) an error is given in strict ANSI
mode, or a warning otherwise.In non-strict ANSI mode, 'type' is allowed to be any expression. */
.....;
break;
case 'd':
case 'i':
vargint = va_arg(vp, int);
.......;
break;
case 'f':
vargflt = va_arg(vp, double);
/* va_arg(ap, type), if type is narrow type (char, short, float) an error is given in strict ANSI
mode, or a warning otherwise.In non-strict ANSI mode, 'type' is allowed to be any expression. */
.......;
break;
case 's':
vargpch = va_arg(vp, char*);
.......;
break;
case 'b':
case 'B':
vargint = va_arg(vp, int);
......;
break;
case 'x':
case 'X':
vargint = va_arg(vp, int);
......;
break;
case '%':
putchar('%');
break;
default:
break;
}
pfmt++;
}
else
{
putchar(*pfmt++);
}
}
va_end(vp);
}
后来,C99编译器既支持可变参数的函数,也支持可变参数的宏:
2 可变参数的宏
#define debug(fmt, …) printf(fmt,__VAR_ARGS__) /*支持可变参数的宏*/
#define debug(fmt, …) printf(fmt,##__VAR_ARGS__) /*支持可变参数的宏,其中可变参数可以为空*/
#define debug(fmt, arg…) printf(fmt,##arg) /*GCC支持给可变参数一个名字,如arg 。当可变参数为空时,##操作使预处理器去除掉它前面的逗号*/
2.1 说明
<1> ... 表示可变参数
<2> __VAR_ARGS__ 保留名,将可变参数 ... 传给宏
<3> arg 可变参数名,代表可变参数列表
2.2 示例
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define FMT_WARN(fmt...) do {if(0) printf(fmt);}while(0)
void _log(const char *domain, const char *file, const char *function, int line, int level, const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
printf(" domain: %s\n", domain);
printf(" file: %s\n", file);
printf("function: %s\n", function);
printf(" line: %d\n", line);
printf(" level: %d\n", level);
vprintf(fmt, arg);
va_end(arg);
}
#define log(dom,level,fmt...) do{ \
FMT_WARN(fmt); \ /*说明:当fmt为空时,编译会出错*/
_log(dom, __FILE__, __FUNCTION__, __LINE__, level, ##fmt); \
}while(0)
#define log_rate(fmt, ...) ({ \
/*printf(fmt);*/ \
/*printf("%d -- %s -- %d\n",__VA_ARGS__);*/ \
log(fmt, ##__VA_ARGS__); \ /*说明:log_rate的参数fmt对应log的dom,可变参数 ... 与log的其他参数对应*/
})