找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3736|回复: 0

可变参数函数的剖析

[复制链接]
发表于 2015-1-4 20:40:43 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
  1. #include<iostream>
  2. #include<cstdarg>
  3. using namespace std;

  4. void func(...);
  5. void func2(int nfirst,...);

  6. void main()
  7. {
  8.         cout<<"This is func:"<<endl;
  9.         func(1,2,3,5,6,-1);
  10.         cout<<"This is func2:"<<endl;
  11.         func2(0,7,4,-1);
  12. }

  13. void func(...)
  14. {
  15.         va_list list;
  16.         va_start(list,list);
  17.         list = list + 12;  //只?所¨´以°?加¨®12的Ì?原-因°¨°从䨮临¢¨´时º¡À变À?量¢?地Ì?址¡¤到Ì?第̨²一°?个?参?数ºy之?间?有®D12个?字Á?节¨²。¡ê
  18.         int n = 0;
  19.         std::cout<<n<<endl;
  20.         while(n != -1)
  21.         {
  22.                 n = va_arg(list,int);
  23.                 std::cout<<n<<endl;
  24.         }
  25.         va_end(list);
  26. }

  27. void func2(int nfirst,...)
  28. {
  29.         va_list list;
  30.         va_start(list,nfirst);
  31.         int n = 0;
  32.         while(n!=-1)
  33.         {
  34.                 n = va_arg(list,int);
  35.                 std::cout<<n<<endl;
  36.         }
  37. }
复制代码
函数的运行结果:
1.png
关于可变参数的剖析,步骤
头文件 #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<const char &>(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  #define va_end _crt_va_end
#define _crt_va_end(ap)      ( ap = (va_list)0 )
最后这个简单了,就是清理门户,让ap不再指向栈中内存。
回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-22 15:44 , Processed in 0.041140 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表