C 的可变参数

来源:互联网 发布:龙芯支持windows 编辑:程序博客网 时间:2024/04/20 14:45

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;

示例:实现自己的printf函数(转载)

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的其他参数对应*/        })


0 0