为何函数形参列表内定义的形参与函数内部定义的变量在内存地址上差了8个字节!
请看图,谢谢

解决方案 »

  1.   

    cdecl调用约定
    cdecl调用约定又称为C调用约定,是C语言缺省的调用约定,它的定义语法是:
    int function (int a ,int b) //不加修饰就是C调用约定
    int __cdecl function(int a,int b)//明确指出C调用约定在写本文时,出乎我的意料,发现cdecl调用约定的参数压栈顺序是和stdcall是一样的,参数首先由有向左压入堆栈。所不同的是,函数本身不清理堆栈,调用者负责清理堆栈。由于这种变化,C调用约定允许函数的参数的个数是不固定的,这也是C语言的一大特色。对于前面的function函数,使用cdecl后的汇编码变成:调用处
    push 1
    push 2
    call function
    add esp,8 注意:这里调用者在恢复堆栈被调用函数_function处
    push ebp 保存ebp寄存器,该寄存器将用来保存堆栈的栈顶指针,可以在函数退出
    时恢复mov ebp,esp 保存堆栈指针mov eax,[ebp + 8H] 堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向a                                                                       add eax,[ebp + 0CH] 堆栈中ebp + 12处保存了b
    mov esp,ebp 恢复esp
    pop ebp
    ret 注意,这里没有修改堆栈。
    MSDN中说,该修饰自动在函数名前加前导的下划线,因此函数名在符号表中被记录为_function,但是我在编译时似乎没有看到这种变化。由于参数按照从右向左顺序压栈,因此最开始的参数在最接近栈顶的位置,因此当采用不定个数参数时,第一个参数在栈中的位置肯定能知道,只要不定的参数个数能够根据第一个后者后续的明确的参数确定下来,就可以使用不定参数,例如对于CRT中的sprintf函数,定义为:int sprintf(char* buffer,const char* format,...)由于所有的不定参数都可以通过format确定,因此使用不定个数的参数是没有问题的。
      

  2.   

    先上个release的截图,此时变成4个字节的了~我看看下面回复
      

  3.   

    其实这个问题和可变参无关;
    我把调用约定去掉,去掉变参,改为写了个普通的函数来测试,控制台工程,int sum2(int first)
    {
    int num = 3; return 0;
    }发现函数形参列表与函数内部定义的第一个变量之间还是有8个不明字节,
    再者,我打开(vc6,Project->Setting->C/C++页->Category选Code Generation,会看到Calling convention下拉列表里就有):_cdecl(它选中着),_fastcall,_stdcall。难得:_cdecl约定是VC6默认的?
    大侠回复的那些个汇编看不懂,能否通俗点说下
      

  4.   

    VC6默认的调用方式是__cdecl C语言调用约定
      

  5.   

    哦,恩,记得了。
    那个大侠caozhy的我都没看懂~