/*X86平台,参数传递是基于堆栈来完成的,对内存使用时连续的*/
void printf_myself(const char *format, ...)
{
/*char *ptr_s = &format;*/
int num; char ch; double d;
struct _student stu;
/*const char *name_str;*/
/*指针操作,1取值,2指针自增(移动指针)*/
/*char *s = format; // char *s = **ptr_s;*/
va_list p;
printf("str = %s\n", format);
va_start(p,format); //取指针变量的值(不是所指向的值),并将指针p自增
num = va_arg(p,int); // 取值 并 移动指针
printf("num = %d\n", num);
stu = va_arg(p,struct _student);
printf("stu.num = %d\n", stu.num);
printf("stu.name = %s\n", stu.name);
printf("stu.age = %d\n", stu.age);
num = va_arg(p,int);
printf("num = %d\n", num);
ch = va_arg(p,int);
printf("ch = %c\n", ch);
d = va_arg(p,double);
printf("num = %f\n", d);
va_end(p);
}
其实实现可变参数列表是如此的简单,哈哈,
一句话来概括就是:
/X86平台,参数传递是基于堆栈来完成的,对内存使用时连续的/
三步走!!!
1,取指针变量的值(不是所指向的值)
va_list p; //va_list 是一个字符指针变量的宏 typedef char * va_list;
va_start(p,format);
这个操作将会取首地址,并使得指针p自增format位
2,取值 并 移动指针
num = va_arg(p,int);
va_arg()这个宏用来取出指针移动后所指向的地址的值,并移动p指针并以int类型移动指向,所以这里是移动4个字节。
va_end§;
最后这句是把p指向了一个空指针,防止野指针。
参考:
INTSIZEOF 宏,获取类型占用的空间长度,最小占用长度为int的整数倍 (除4取整):
define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//这里 &上~(sizeof(int) - 1),也就是&上3取反,意思是清0掉低两位(相当于除4取整),因为没有用到系统或库函数实现的软件除法 所以才这么用
//另外 加 “+ sizeof(int) - 1” 是为了向上取整
VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):
define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):
define va_arg(ap,t) ( *(t *) ((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
VA_END宏,清空va_list可变参数列表:
define va_end(ap) ( ap = (va_list)0 )
最后,欢迎留言讨论,请多多指教!