C/C++中几种函数调用方式的比较

1. cdecl: C的函数默认调用方式, 适用可变参数,这种方式由于是 函数调用者清理堆栈,所以又导致了生成代码增长(因为每次函数调用之后都是实现清理功能的代码,如果是函数自己清理,则只需要一份清理代码就可以了)

2. stdcall:  函数清理堆栈,不可用于可变参数

3. fastcall:  类似stdcall, 但把因为它是通过寄存器 传送参数的(实际上,它用ECX和EDX传送前两个单字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈 )。
 
基于在不同函数调用方式下的汇编生成代码作比较:(用VS反汇编生成,看标红代码即可)
int func(int val1,int val2,int val3)
{
	int a;
	a=val1;
	return a;		
}

b=func(1,2,3);  //调用语句

--------cdecl------------
func:
.........
004113BE  mov         eax,dword ptr [val1] 
004113C1  mov         dword ptr [a],eax 
004113C4  mov         eax,dword ptr [a] 
.........
004113CD   ret         

b=func(1,2,3):
004113FE  push        3    
00411400  push        2    
00411402  push        1    
00411404  call        func (411028h) 
00411409   add         esp,0Ch 
0041140C  mov         dword ptr [b],eax 


说明: cdecl是函数调用者清理参数(add esp,0Ch,把栈指针加3个int长度的偏移,实现参数的清理,如果是类对象还要析构
--------cdecl------------



--------stdcall------------
func:
.........
004113BE  mov         eax,dword ptr [val1] 
004113C1  mov         dword ptr [a],eax 
004113C4  mov         eax,dword ptr [a] 
......... 
004113CD   ret         0Ch 

b=func(1,2,3):
004113FE  push        3    
00411400  push        2    
00411402  push        1    
00411404  call        func (411028h) 
00411409  mov         dword ptr [b],eax


说明: stdcall是函数自己清理参数(注意此时堆栈指针esp是指向返回地址的,返回地址下面是参数,指令 ret OCh使 函数返回再给 esp加上3个int长度的偏移来清理参数
--------stdcall------------



--------fastcall------------
func:
.........
004113BF   pop         ecx   
004113C0   mov         dword ptr [ebp-14h],edx 
004113C3   mov         dword ptr [ebp-8],ecx 
004113C6  mov         eax,dword ptr [val1] //这里val1==ebp-8
004113C9  mov         dword ptr [a],eax 
004113CC  mov         eax,dword ptr [a] 
.........  
004113D5   ret         4 

b=func(1,2,3):
0041140E  push        3    
00411410   mov         edx,2 
00411415   mov         ecx,1 
0041141A  call        func (4110B4h) 
0041141F  mov         dword ptr [b],eax


说明: fastcall是通过ecx和edx来传递前 两个单字(DWORD)或更小的参数 ,如这里用ecx传递1( mov ecx,1 ),edx传递2(mov edx,2 ), 它的栈中参数清理工作是跟stdcall一样的,只是这里只需要清理一个参数就可以了(ret   4 
--------fastcall------------


总结:
1.cdecl和stdcall好理解,如果不需要可变参数的话,stdcall是好的选择。
2.fastcall的作用有点不好理解,从上面的代码看,看不出有多么快速。。

待续。。   
原文地址:https://www.cnblogs.com/javawebsoa/p/3098030.html