可变参数函数

来源:互联网 发布:js回调函数原理 编辑:程序博客网 时间:2024/06/06 04:41

C程序例子:为了了解可变参数函数汇中,参数读取的具体步骤,在add函数中本别用三个变量a,b,c来读取对应的参数。但在应用中,可用for循环,循环num次读取参数。

#include<stdio.h>#include<stdlib.h>#include<stdarg.h>//包含了va_list等宏,用于处理可变参数的函数//typedef char* valist; char指针类型int add(int num,...)//int num 告诉编译器函数有多少个参数,...代表参数可变{    int result = 0;    int a,b,c;    va_list argp;//typedef char *  va_list; 创建一个指针    va_start(argp,num);//开始读取num个参数,读取结束后在把地址放在argp中    a = va_arg(argp,int);//va_arg()读取参数    b = va_arg(argp,int);    c = va_arg(argp,int);    va_end(argp);    return a+b+c;}void main(){    int x = 3;    int r;    r = add(3,1,3,3);//    printf("%d\n",r);    getchar();}

可变参数分析:

  1. 首先要包含stdarg.h的头文件,因为里面包含处理可变参数函数的宏
  2. 可变参数函数的定义中至少定义一个参数,…代表可变参数。这个参数用于告诉编译器该函数还要传递的参数的个数,而且该参数在堆栈中的地址可用于定位其他参数的位置(因为上一个博客中已经得出这些参数是按顺序压入栈中的,而且存储单元是紧挨着的)。
  3. 可变参数函数读取实参的步骤:
    1). va_list argp;//typedef char * va_list; 创建一个指针;PS:va = variable argument,创建的 指针共va_start和va_end使用
    2).va_start(argp,num);//开始读取参数,argp指向除num外的最左边的参数
    a =va_arg(argp,int);//按整数类型,从对应的堆栈中读取参数,argp+=4,argp指向b;
    b = va_arg(argp,int);//按整数类型,从对应的堆栈中读取参数,argp+=4,argp指向c;
    c =va_arg(argp,int);//按整数类型,从对应的堆栈中读取参数,argp+=4,;
    va_end(argp);//结束读取,argp = 0;


    以下为对应反汇编程序及相应的注释

r = add(3,1,3,3);//004010CF   push        3                      //地址:0018FEEC004010D1   push        3                      //地址:0018FEE8004010D3   push        1                      //地址:0018FEE4004010D5   push        3                      //地址:0018FEE0004010D7   call        @ILT+0(_add) (00401005)//函数返回地址0018FEDC@ILT+0(_add):00401005   jmp         add (00401020)int add(int num,...)                          //int num 告诉编译器函数有多少个参数,...代表参数可变8:    {00401020   push        ebp                    //地址:0018FED800401021   mov         ebp,esp                //此时ebp = 0018FED800401023   sub         esp,54h00401026   push        ebx00401027   push        esi00401028   push        edi00401029   lea         edi,[ebp-54h]0040102C   mov         ecx,15h00401031   mov         eax,0CCCCCCCCh00401036   rep stos    dword ptr [edi]9:        int result = 0.0;00401038   mov         dword ptr [ebp-4],010:       int a,b,c;11:       va_list argp;                         //typedef char *  va_list; 创建一个指针12:13:       va_start(argp,num);                   //开始读取num个参数,读取结束后在把地址放在argp中0040103F   lea         eax,[ebp+0Ch]            //0018FEE4 1的地址00401042   mov         dword ptr [ebp-14h],eax  //把1的地址即出num外的左边的第一个参数的地址赋值给argp14:       a = va_arg(argp,int);00401045   mov         ecx,dword ptr [ebp-14h]00401048   add         ecx,4                    //0018FEE8 2的地址,总是按int类型指向下一个单元0040104B   mov         dword ptr [ebp-14h],ecx0040104E   mov         edx,dword ptr [ebp-14h]00401051   mov         eax,dword ptr [edx-4]    00401054   mov         dword ptr [ebp-8],eax    //读取0018FEE4 即1的值15:       b = va_arg(argp,int);00401057   mov         ecx,dword ptr [ebp-14h]0040105A   add         ecx,4                    //0018FEEC 3的地址,总是按int类型指向下一个单元0040105D   mov         dword ptr [ebp-14h],ecx00401060   mov         edx,dword ptr [ebp-14h]00401063   mov         eax,dword ptr [edx-4]00401066   mov         dword ptr [ebp-0Ch],eax  //读取0018FEE8 即1的值16:       c = va_arg(argp,int);00401069   mov         ecx,dword ptr [ebp-14h]0040106C   add         ecx,4                     //0018FEF0 ,总是按int类型指向下一个单元0040106F   mov         dword ptr [ebp-14h],ecx00401072   mov         edx,dword ptr [ebp-14h]00401075   mov         eax,dword ptr [edx-4]00401078   mov         dword ptr [ebp-10h],eax17:       va_end(argp);0040107B   mov         dword ptr [ebp-14h],0     //结束参数读取,对argp重新赋值18:       return a+b+c;00401082   mov         eax,dword ptr [ebp-8]00401085   add         eax,dword ptr [ebp-0Ch]00401088   add         eax,dword ptr [ebp-10h]19:20:   }
0 0
原创粉丝点击