C库中对函数的可变参数的支持
C语言在<stdarg.h> 头文件定义了一些宏,当函数参数未知时去获取函数的参数。
包括一个va_list类型和三个函数(宏)va_start, va_arg和va_end .
变量和定义
va_list类型通过stdarg宏定义来访问一个函数的参数表,参数列表的末尾会用省略号省略
声明:void va_start(va_list ap, last_arg);
用va_arg和va_end宏初始化参数ap,last_arg是传给函数的固定参数的最后一个,省略号之前的那个参数注意va_start必须在使用va_arg和va_end之前调用
声明:type va_arg(va_list ap, type);
用type类型扩展到参数表的下个参数
注意ap必须用va_start初始化,如果没有下一个参数,结果会是undefined
声明:void va_end(va_list ap); 允许一个有参数表(使用va_start宏)的函数返回,如果返回之前没有调用va_end,结果会是undefined。参数变量列表可能不再使用(在没调用va_start的情况下调用va_end)
windows下的定义如下:
其中比较不容易理解的就是_INTSIZEOF宏:其实_INTSIZEOF(n)表示得到变量n的内存大小,这里要考虑内存对齐问题,在32位中系统中,一般是4字节(32位)对齐。(sizeof(n) + sizeof(int))表示凑成4字节的整数被,(sizeof(n) + sizeof(int)) & (sizeof(int) -1)表示将凑齐后多余的字节删除。比如说10字节的变量,占内存的大小为:(10+4)&((11111100)2)= 12字节;
C语言中利用可变参数的函数就是最常用的printf。而且C标准库中也是包括3个参数含有va_list的函数:vprintf,vfprintf,vsprintf。而这三个函数与对应的不加“v“的函数用法是一样的,只不过,vprintf类要求可变参数用va_list指定。其实printf就是利用vprintf来实现的。
下面是一个模仿printf的函数:
包括一个va_list类型和三个函数(宏)va_start, va_arg和va_end .
变量和定义
va_list类型通过stdarg宏定义来访问一个函数的参数表,参数列表的末尾会用省略号省略
声明:void va_start(va_list ap, last_arg);
用va_arg和va_end宏初始化参数ap,last_arg是传给函数的固定参数的最后一个,省略号之前的那个参数注意va_start必须在使用va_arg和va_end之前调用
声明:type va_arg(va_list ap, type);
用type类型扩展到参数表的下个参数
注意ap必须用va_start初始化,如果没有下一个参数,结果会是undefined
声明:void va_end(va_list ap); 允许一个有参数表(使用va_start宏)的函数返回,如果返回之前没有调用va_end,结果会是undefined。参数变量列表可能不再使用(在没调用va_start的情况下调用va_end)
windows下的定义如下:
#ifndef _VA_LIST_DEFINED
#ifdef _M_ALPHA
typedef struct {
char *a0; /* pointer to first homed integer argument */
int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif
#define _VA_LIST_DEFINED
#endif
#ifdef _M_IX86
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_MRX000)
#ifdef _M_ALPHA
typedef struct {
char *a0; /* pointer to first homed integer argument */
int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif
#define _VA_LIST_DEFINED
#endif
#ifdef _M_IX86
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_MRX000)
其中比较不容易理解的就是_INTSIZEOF宏:其实_INTSIZEOF(n)表示得到变量n的内存大小,这里要考虑内存对齐问题,在32位中系统中,一般是4字节(32位)对齐。(sizeof(n) + sizeof(int))表示凑成4字节的整数被,(sizeof(n) + sizeof(int)) & (sizeof(int) -1)表示将凑齐后多余的字节删除。比如说10字节的变量,占内存的大小为:(10+4)&((11111100)2)= 12字节;
C语言中利用可变参数的函数就是最常用的printf。而且C标准库中也是包括3个参数含有va_list的函数:vprintf,vfprintf,vsprintf。而这三个函数与对应的不加“v“的函数用法是一样的,只不过,vprintf类要求可变参数用va_list指定。其实printf就是利用vprintf来实现的。
下面是一个模仿printf的函数:
#include <stdio.h>
#include <stdarg.h>
void print(char* fmt,...){
va_list ap;
int d;
char c,*s;
double f;
va_start(ap, fmt);
while(*fmt)
switch(*fmt++){
case 's':
s=va_arg(ap,char*);
printf("string: %s\n",s);
break;
case 'd':
d=va_arg(ap,int);
printf("int: %d\n",d);
break;
case 'c':
c=(char)va_arg(ap,int);
printf("char: %c\n",c);
break;
case 'f':
f=va_arg(ap,double);
printf("double: %f\n",f);
break;
}
va_end(ap);
}
int main(){
char* s="hello world";
char c='H';
int d=333;
double f=79.998;
print("%s %d %c %f",s,d,c,f);
}
#include <stdarg.h>
void print(char* fmt,...){
va_list ap;
int d;
char c,*s;
double f;
va_start(ap, fmt);
while(*fmt)
switch(*fmt++){
case 's':
s=va_arg(ap,char*);
printf("string: %s\n",s);
break;
case 'd':
d=va_arg(ap,int);
printf("int: %d\n",d);
break;
case 'c':
c=(char)va_arg(ap,int);
printf("char: %c\n",c);
break;
case 'f':
f=va_arg(ap,double);
printf("double: %f\n",f);
break;
}
va_end(ap);
}
int main(){
char* s="hello world";
char c='H';
int d=333;
double f=79.998;
print("%s %d %c %f",s,d,c,f);
}