C++ 可变参数的函数
2013-10-15 10:13
537 查看
C++ 中可变参数的函数有两种类型:
type func(...)
type func(type,...)
可变参数顾名思义就是函数的参数数目或者类型是不确定的,对于这种该如何获取传递的参数的值,这就需要对C,C++的函数栈结构有一定的了解。下面就直接进入实战分析:
函数的运行结果:
关于可变参数的剖析,步骤
头文件 #include<cstdarg>
宏定义 va_list,va_start,va_arg,va_end
步骤:
1 va_list ap
标识一个数据结构,ap用来存放可变参数信息。
2 va_start(ap,v);
这个宏用来初始化可变参数列表。ap表示初始化的数据结构,它里面存放着后面的可变参数信息。 v标识函数声明中最后一个具有名字的参数,也就是...之前的那个参数。
3 va_arg(ap,t);
获取可变参数,t是参数的类型。用这个函数来获取后面的可变参数的值。
int xx;
xx = va_arg(ap,int);
4 va_end(ap);
这个宏用来宣告可变参数调用的结束,要用在最后面。
再来看宏的解释:
1 typedef
char * va_list;
说明va_list 是一个char*类型的。
2 #define va_start _crt_va_start
#define_crt_va_start(ap,v) ( ap =(va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _ADDRESSOF(v) ( &reinterpret_cast<constchar&>(v) )
#define _INTSIZEOF(n) ( (sizeof(n)+sizeof(int) -1) & ~(sizeof(int)-
1) )
这个是为了内存对齐。什么叫做内存对齐呢?我们知道任何正整数都可以表达为
x = n*q + r , ( 0≤r<q ),
对齐就是要当r = 0 时,x = n*q。当 r>0 时候,x = ( n + 1 )*q
所以对于最终要求的结果 x ,我们可以得出这样的表达式:
x = n*q + r , ( -q<r≤0 )
方程的两边都加上 q-1 得:
x + q - 1 = n*q + (r + q - 1), ( 0≤r + q - 1<q )
其中的n*q 就是我们最终要求的结果,那么n*q的结果就可以表示为:
(x + q - 1)/q*q = n*q.
如果 q是2进制的整数次幂,事情就更加好办了. 假设 q = 2^k,那么只需要把(x + q - 1)的0-m-1次位清零即可。即:
(x + q -1 )&~(q-1).
从以上可以得出va_list 是为了得出可变参数中第一个元素的地址,从这里也可以看出,参数v必须是命名参数中的最后一个参数。
3 #define va_arg _crt_va_arg
#define_crt_va_arg(ap,t) ( *(t *)((ap +=_INTSIZEOF(t)) - _INTSIZEOF(t)) )
(ap +=_INTSIZEOF(t)) //实现ap的值偏移
(ap +=_INTSIZEOF(t)) - _INTSIZEOF(t)) //实现把地址定位到参数的指向地址
(t *)((ap +=_INTSIZEOF(t)) - _INTSIZEOF(t)) //强制类型转换成参数的类型
( *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //取出参数的值
4 #defineva_end _crt_va_end
#define_crt_va_end(ap) ( ap = (va_list)0 )
最后这个简单了,就是清理门户,让ap不再指向栈中内存。
type func(...)
type func(type,...)
可变参数顾名思义就是函数的参数数目或者类型是不确定的,对于这种该如何获取传递的参数的值,这就需要对C,C++的函数栈结构有一定的了解。下面就直接进入实战分析:
#include<iostream> #include<cstdarg> using namespace std; void func(...); void func2(intnfirst,...); void main() { cout<<"Thisis func:"<<endl; func(1,2,3,5,6,-1); cout<<"Thisis func2:"<<endl; func2(0,7,4,-1); } void func(...) { va_list list; va_start(list,list); list = list + 12; //只?所¨´以°?加¨®12的Ì?原-因°¨°从䨮临¢¨´时º¡À变À?量¢?地Ì?址¡¤到Ì?第̨²一°?个?参?数ºy之?间?有®D12个?字Á?节¨²。¡ê int n =0; std::cout<<n<<endl; while(n!= -1) { n = va_arg(list,int); std::cout<<n<<endl; } va_end(list); } void func2(intnfirst,...) { va_list list; va_start(list,nfirst); int n =0; while(n!=-1) { n = va_arg(list,int); std::cout<<n<<endl; } }
函数的运行结果:
关于可变参数的剖析,步骤
头文件 #include<cstdarg>
宏定义 va_list,va_start,va_arg,va_end
步骤:
1 va_list ap
标识一个数据结构,ap用来存放可变参数信息。
2 va_start(ap,v);
这个宏用来初始化可变参数列表。ap表示初始化的数据结构,它里面存放着后面的可变参数信息。 v标识函数声明中最后一个具有名字的参数,也就是...之前的那个参数。
3 va_arg(ap,t);
获取可变参数,t是参数的类型。用这个函数来获取后面的可变参数的值。
int xx;
xx = va_arg(ap,int);
4 va_end(ap);
这个宏用来宣告可变参数调用的结束,要用在最后面。
再来看宏的解释:
1 typedef
char * va_list;
说明va_list 是一个char*类型的。
2 #define va_start _crt_va_start
#define_crt_va_start(ap,v) ( ap =(va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _ADDRESSOF(v) ( &reinterpret_cast<constchar&>(v) )
#define _INTSIZEOF(n) ( (sizeof(n)+sizeof(int) -1) & ~(sizeof(int)-
1) )
这个是为了内存对齐。什么叫做内存对齐呢?我们知道任何正整数都可以表达为
x = n*q + r , ( 0≤r<q ),
对齐就是要当r = 0 时,x = n*q。当 r>0 时候,x = ( n + 1 )*q
所以对于最终要求的结果 x ,我们可以得出这样的表达式:
x = n*q + r , ( -q<r≤0 )
方程的两边都加上 q-1 得:
x + q - 1 = n*q + (r + q - 1), ( 0≤r + q - 1<q )
其中的n*q 就是我们最终要求的结果,那么n*q的结果就可以表示为:
(x + q - 1)/q*q = n*q.
如果 q是2进制的整数次幂,事情就更加好办了. 假设 q = 2^k,那么只需要把(x + q - 1)的0-m-1次位清零即可。即:
(x + q -1 )&~(q-1).
从以上可以得出va_list 是为了得出可变参数中第一个元素的地址,从这里也可以看出,参数v必须是命名参数中的最后一个参数。
3 #define va_arg _crt_va_arg
#define_crt_va_arg(ap,t) ( *(t *)((ap +=_INTSIZEOF(t)) - _INTSIZEOF(t)) )
(ap +=_INTSIZEOF(t)) //实现ap的值偏移
(ap +=_INTSIZEOF(t)) - _INTSIZEOF(t)) //实现把地址定位到参数的指向地址
(t *)((ap +=_INTSIZEOF(t)) - _INTSIZEOF(t)) //强制类型转换成参数的类型
( *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //取出参数的值
4 #defineva_end _crt_va_end
#define_crt_va_end(ap) ( ap = (va_list)0 )
最后这个简单了,就是清理门户,让ap不再指向栈中内存。
相关文章推荐
- C/C++可变参数函数
- C++ 可变参数函数
- C++可变参数的函数
- C++学习之可变参数的函数与模板
- C++可变参数函数( 如:void Func(int a, int b, ...) )用法
- C++:可变参数函数
- C/C++中可变参数函数的实现
- C++学习之可变参数的函数与模板
- C,C++ 可变参数函数例子
- 【日积月累】C/C++可变参数函数的实现
- C++ 编码军规(001):不要使用包含可变参数列表的函数
- c/c++支持可变参数的函数
- C++函数可变参数实现原理探究——以实现printf为例
- 【C++基础之二十】可变参数的函数
- C/C++ 实现可变参数的函数
- 今天学习了关于C++ 中可变参数个数函数的使用!
- C语言中的可变参数-printf的实现原理 在C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出
- C和C++中处理个数可变的可选参数的函数和宏
- C/C++中用va_start/va_arg/va_end实现可变参数函数的原理与实例详解
- [C/C++]函数参数的入栈顺序与可变参数的实现