WEB开发网
开发学院软件开发VC 从printf谈可变参数函数的实现 阅读

从printf谈可变参数函数的实现

 2008-08-09 19:25:55 来源:WEB开发网   
核心提示: va_start(ap, A){ char *ap =((char *)(&A)) + sizeof(A)并int类型大小地址对齐}在printf的va_start(args, fmt)中,fmt的类型为char *, 因此对于一个32为系统 sizeof(char *) = 4, 如果i

  va_start(ap, A)
  {
     char *ap = ((char *)(&A)) + sizeof(A)并int类型大小地址对齐
  }
  在printf的va_start(args, fmt)中,fmt的类型为char *, 因此对于一个32为系统 sizeof(char *) = 4, 如果int大小也是32,则va_start(args, fmt);相当于 char *args = (char *)(&fmt) + 4; 此时args的值正好为fmt后第一个参数的地址。对于如下的可变参数函数  void fun(double d,...)
  {
    va_list args;
    int n;
    va_start(args, d);
  }
则 va_start(args, d);相当于  char *args = (char *)&d + sizeof(double);  此时args正好指向d后面的第一个参数。

可变参数函数的实现与函数调用的栈结构有关,正常情况下c/c++的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈。对于函数

  void fun(int a, int b, int c)
  {
    int d;
    ...
  }
其栈结构为  0x1ffc-->d
  0x2000-->a
  0x2004-->b
  0x2008-->c
  对于任何编译器,每个栈单元的大小都是sizeof(int), 而函数的每个参数都至少要占一个栈单元大小,如函数 void fun1(char a, int b, double c, short d) 对一个32的系统其栈的结构就是  0x1ffc-->a (4字节)
  0x2000-->b (4字节)
  0x2004-->c (8字节)
  0x200c-->d (4字节)
  对于函数void fun1(char a, int b, double c, short d)

如果知道了参数a的地址,则要取后续参数的值则可以通过a的地址计算a后面参数的地址,然后取对应的值,而后面参数的个数可以直接由变量a指定,当然也可以像printf一样根据第一个参数中的%模式个数来决定后续参数的个数和类型。如果参数的个数由第一个参数a直接决定,则后续参数的类型如果没有变化并且是已知的,则我们可以这样来取后续参数, 假定后续参数的类型都是double;

Tags:printf 可变 参数

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接