函数命名规则及调用约定(__cdecl,__stdcall,__fastcall)

来源:互联网 发布:c语言正弦函数数列求和 编辑:程序博客网 时间:2024/05/01 08:18

函数命名规则及调用约定(__cdecl,__stdcall,__fastcall)

__cdecl是C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。
__stdcall调用约定用于调用Win32 API函数。采用__stdcall约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__stdcall可以写成_stdcall。

__fastcall约定用于对性能要求非常高的场合。__fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。__fastcall可以写成_fastcall

函数返回值传递方式

   其实,返回值的传递从处理上也可以想象为函数调用的一个out形参数; 函数返回值传递方式也是函数调用约定的一部分;
   有返回值的函数返回时:一般int、指针等32bit数据值(包括32bit结构)通过eax传递,(bool,char通过al传递,short通过ax传递),特别的__int64等64bit结构(struct) 通过edx,eax两个寄存器来传递(同理:32bit整形在16bit环境中通过dx,ax传递); 其他大小的结构(struct)返回时把其地址通过eax返回;(所以返回值类型不是1,2,4,8byte时,效率可能比较差)
   参数和返回值传递中,引用方式的类型可以看作与传递指针方式相同;

   float\double(包括Delphi中的extended)都是通过浮点寄存器st(0)返回;

下面是几个例子:

global      _GetPowerAsm@8_GetPowerAsm@8:            PUSH    EBP             ; Save EBP            MOV     EBP, ESP        ; Move ESP into EBP so we can refer                                    ; to arguments on the stack            MOV     EAX, [EBP+4]    ; Get first argument            MOV     ECX, [EBP+6]    ; Get second argument            SHL     EAX, CL         ; EAX = EAX * (2 ^ CL)            POP     EBP             ; Restore EBP            RET 8            ;被调用者平衡堆栈               global      _GetPowerAsm_GetPowerAsm:            PUSH    EBP             ; Save EBP            MOV     EBP, ESP        ; Move ESP into EBP so we can refer                                    ; to arguments on the stack            MOV     EAX, [EBP+4]    ; Get first argument            MOV     ECX, [EBP+6]    ; Get second argument            SHL     EAX, CL         ; EAX = EAX * (2 ^ CL)            POP     EBP             ; Restore EBP            RET                     ;调用者平衡堆栈    global _sums@12  ;全局函数声明,表示这个函数要被外部文件调用_sums@12: push ebp        ;保护ebp指针 mov ebp,esp mov eax,[ebp+8] ;第一个入口参数int VAR1 add eax,[ebp+12];第二个入口参数相加int VAR2  add eax,[ebp+16];第三个入口参数相加int VAR3  pop ebp         ;恢复ebp指针 ret 12           ;被调用者平衡堆栈global _sums  ;全局函数声明,表示这个函数要被外部文件调用_sums: push ebp        ;保护ebp指针 mov ebp,esp mov eax,[ebp+8] ;第一个入口参数int VAR1 add eax,[ebp+12];第二个入口参数相加int VAR2  add eax,[ebp+16];第三个入口参数相加int VAR3  pop ebp         ;恢复ebp指针 ret            ;调用者平衡堆栈