注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

云水居

云在青山水在天,人在江湖不得闲

 
 
 

日志

 
 

C语言函数的可变长度参数va_arg剖析  

2010-10-21 10:00:12|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

查看全文


C语言的printf函数,可以输入不同的参数,一般通过函数重载的方式实现这种函数名相同而参数不同的机制,但考虑到printf的所有可能性,函数重载很明显解决不了这个问题,printf 和vsprintf 使用了可变长度参数来实现这种机制。
先看一个典型作用
void f(int flag, ...){
    va_list args;
    va_start(args, flag);
    int n = va_arg(args, int);
}
C语言的函数调用机制
C语言的函数调用机制,是将函数参数与函数调用后下一条指令的地址都压入栈中,然后跳到函数的入口地址。
C语言函数的可变长度参数va_arg剖析 - hankjin - 云水居
例如
void func(int param1, double param2,int param3){ }
int main(){
  func(3, 1.2, 4);
  printf("Over\n"); //设指令地址为0x1234
  return 0;
}
执行f(3, 1.2, 4)的函数调用,进入func函数时的堆栈如下:
C语言函数的可变长度参数va_arg剖析 - hankjin - 云水居
 这样,通过param1的地址就可以计算出param2与param3的地址:
&param2 = ((char*)&param1) + sizeof(param2)
所以...只是对后面的参数的一种省略的写法,只要我们在程序中进行相应的计算与类型转换,就可以得到每个参数的值。
模拟实现
//方法一
void func(int param1, double param2, int param3){
  double *p2 = (double*)  ((char*) param1) + sizeof(param1);
  int *p3 = (int*) ((char*)param1)+sizeof(param1)+sizeof(param2);
}
//方法二
void func(int param1, double param2, int param3){
  char * p;
  p = (char*)&param1 + sizeof(param1);//参数一的结尾
  p+= sizeof(double);//参数二的结尾
  double *p2 = (double*)  (p - sizeof(double);
  p+=sizeof(int);//参数三的结尾
  int *p3 = (int*) (p-sizeof(int);
}
这样就可以猜测va_list va_start va_arg va_end的实现
va_list  声明一个指针变量,跟踪当前参数的指针;
va_start 初始化这个指针的位置,最开始指向第一个参数的结尾的位置
va_arg 则移动指针,指向一个新参数的位置,并返回当前值
void func(int param1, double param2, int param3){
  va_list p;
  va_start(p, param1);
  double p2 = va_arg(double);
  double p3 = va_arg(int);
}
再和方法二的实现进行对照
可以预测
va_list <-> char *
va_start <-> p=&beginparam
va_arg <-> x=*p, p+=sizeof(x)
va_end做了什么?
Linux的实现方法
查看Linux0.11的内核源代码,对va_list, va_start, va_arg 的实现如下:
1. va_list的实现没有差别,char*
typedef char *va_list;
2. va_start的实现
#define va_start(AP, LASTARG)                                           \
 (__builtin_saveregs (),              &n

查看全文

  评论这张
 
阅读(2133)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017