您的位置:首页 > 编程语言 > C语言/C++

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

2013-05-24 22:56 344 查看
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 ,eax

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

--------cdecl------------

--------stdcall------------

[b]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 ,eax

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


--------stdcall------------

--------fastcall------------

[b]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的作用有点不好理解,从上面的代码看,看不出有多么快速。。

待续。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: