C语言可变参
必需掌握的1个自定义类型和3个宏函数
<一种自定义类型> va_list
用来定义,存放““可变参数列表”的地址”的变量
原型:
typedef char * va_list;
<宏函数> va_start(va_list 表指针,最后一个“确定参数”)
将表头地址赋值给表指针
原型:
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
<宏函数> va_arg(va_list 表指针,参数类型)
根据表指针和参数类型,依次返回数据(表指针每次调用,自动完成自偏移)
原型:
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
<宏函数> va_end(va_list 表指针)
将表指针赋值为NULL
原型:
#define va_end(ap) ( ap = (va_list)0 )
备注
上面的原型来自于(X86 VC)stdarg.h中。
由于1)硬件平台的不同2)编译器的不同,所以定义的宏也有所不同,仅供参考。
从内存角度分析
C语言的函数是从右向左的顺序入栈的,如下图所示是x86的
(这是x86的,ARM和这个相反,是从左向右)
高地址 |-----------------------------|
|函数返回地址 |
|-----------------------------|
|.............................|
|-----------------------------|<--va_arg后ap指向
|第n个参数(第一个可变参数) |
|-----------------------------|<--va_start后ap指向
|第n-1个参数(最后一个固定参数) |<-- &v
|.............................|
|第1个参数(第一个固定参数) |
低地址 |-----------------------------|
例子
#include <stdio.h>;
#include <string.h>;
typedef char * va_list;
#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 )
int demo(char *msg, ... )
{
va_list argp;
int argno = 0;
char *para;
va_start( argp, msg );
while (1)
{
para = va_arg( argp, char *);
if ( strcmp( para, "\0") == 0 )
break;
printf("Parameter #%d is: %s \n", argno, para);
argno++;
}
va_end( argp );
return 0;
}
int main( void )
{
demo("DEMO", "This", "is", "a", "demo!" ,"333333", "\0");
return 0;
}