(本章节中例子都是用 VS2005 编译调试的)
宏定义:
// vadefs.h #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
宏定义:
// vadefs.h #define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
宏定义:
// stdarg.h #define va_start _crt_va_start // vadefs.h #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
作用: 使 va_list 指向起始的参数
参数:
宏定义:
// stdarg.h #define va_arg _crt_va_arg // vadefs.h #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
作用: 检索参数,每次提取一次可变参数,arg 就向上移动一次.无论它现在指向的是不是参数它都会读取arg参数里存放地址里的内容
参数:
宏定义:
// stdarg.h #define va_end _crt_va_end // vadefs.h #define _crt_va_end(ap) ( ap = (va_list)0 )
作用: 释放 va_list
参数: ap 为 va_list 类型的变量
定义:
// stdarg.h typedef char * va_list;
形式:
参数解释:
使用可变参数的下步骤
C 语言的函数是从右向左压入堆栈的,下图是函数的参数在堆栈中的分布位置:
输出所有int型态的参数,直到-1结束:
1 #include<iostream> 2 #include <cstdarg> 3 using namespace std; 4 5 void printargs(int arg1,...) 6 { 7 va_list ap; 8 //声明变量 ap,用于指向参数 9 int i; 10 va_start(ap,arg1); 11 //获得第一个参数的地址 12 //va_start(ap,arg1); 把宏展开来看等价于 13 //(ap =(char*)(&reinterpret_cast<const char&>(arg1))+((sizeof(arg1)+sizeof(int)-1)&~(sizeof(int)- 1))); 14 for(i=arg1;i!=-1;i=va_arg(ap,int)) 15 //va_arg(ap,int) 把宏展开来看等价于 16 //(*(int*)((ap +=((sizeof(int)+sizeof(int)- 1)&~(sizeof(int)- 1)))-((sizeof(int)+sizeof(int)- 1) &~(sizeof(int)- 1)))) 17 //输出所有int型态的参数,直到-1结束 18 cout<<i<<' '; 19 va_end(ap); 20 //va_end(ap); 把宏展开来看等价于 21 //(ap =(char*)0) 22 cout<<endl; 23 } 24 int main(void) 25 { 26 printargs(5,2,14,84,97,15,24,48,-1); 27 printargs(84,51,-1); 28 printargs(-1); 29 printargs(1,-1); 30 system("pause"); 31 return 0; 32 }
输出结果:
5 2 14 84 97 15 24 48
84 51
1
请按任意键继续. . .
用可变参数第一参数为参数的长度说明:
1 #include<iostream> 2 #include <cstdarg> 3 using namespace std; 4 5 void output(int n, ...); 6 void main() 7 { 8 output(3,"王一",12,"李二",5,"赵三",58); 9 system("pause"); 10 } 11 void output(int n, ...) 12 { 13 va_list ap; 14 va_start(ap,n); //起到初始化,使用得 ap 指向可变参数的第一个参数,即 n 处 15 while(n--) 16 { 17 char* name=va_arg(ap,char*); 18 //获得当前 ap 所指向的参数,并使 ap 指向可变参数的下一个参数,并且要指明获得的参数类型char* 为需要获得的参数的类型. 19 int age=va_arg(ap,int); //同上,int为参数类型 20 cout<<"name :"<<name<<",age="<<age<<endl; 21 } 22 va_end(ap); //结束可变参数获取 23 }
输出结果:
name :王一,age=12
name :李二,age=5
name :赵三,age=58
请按任意键继续. . .
若把上例子中的函数调用由 output(3,"王一",12,"李二",5,"赵三",58); 改为output(3,"王一",12,"李二",5); 时候输出结果变成了这样(在参数后面还有跟着一些函数的相关信息):
name :王一,age=12
name :李二,age=5
name :兡 ?0@,age=1
请按任意键继续. . .
若把上例子中的函数调用由 output(3,"王一",12,"李二",5,"赵三",58); 改为output(3,"王一",12,"李二"); 时候输出结果变成了这样(错误说明:读取的地址无效,.va_arg 提取地址发生错误):
若把上例子中的函数调用由 output(3,"王一",12,"李二",5,"赵三",58); 改为output(3,"王一",12); 时候输出结果变成了这样(在参数后面还有跟着一些函数的相关信息):
name :王一,age=12
name :兡 ?0@,age=1
name :萐;,age=3880944
请按任意键继续. . .
若把上例子中的函数调用由 output(3,"王一",12,"李二",5,"赵三",58); 改为output(3); 时候输出结果变成了这样( 错误说明:读取的地址无效.va_arg 提取地址发生错误):
若把上例子中的函数调用由 output(3,"王一",12,"李二",5,"赵三",58); 改为output(n); 并且 n>3 时候输出结果和上面一样( 错误说明:读取的地址无效.va_arg 提取地址发生错误)