C/C++中几种函数调用方式的比较
2013-05-24 22:56
344 查看
1. cdecl: C的函数默认调用方式, 适用可变参数,这种方式由于是 函数调用者清理堆栈,所以又导致了生成代码增长(因为每次函数调用之后都是实现清理功能的代码,如果是函数自己清理,则只需要一份清理代码就可以了)
2.
stdcall:
函数清理堆栈,不可用于可变参数。
3.
fastcall: 类似stdcall, 但把因为它是通过寄存器
来传送参数的(实际上,它用ECX和EDX传送前两个单字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈 )。
基于在不同函数调用方式下的汇编生成代码作比较:(用VS反汇编生成,看标红代码即可)
--------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的作用有点不好理解,从上面的代码看,看不出有多么快速。。
待续。。
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的作用有点不好理解,从上面的代码看,看不出有多么快速。。
待续。。
相关文章推荐
- C/C++:函数的编译方式与调用约定以及extern “C”的使用
- C/C++:函数的编译方式与调用约定以及extern “C”的使用
- C/C++:函数的编译方式与调用约定以及extern “C”的使用
- 几种函数调用方式
- C++函数编译的几种方式解析
- .NET工程中以 C 和 C++ 两种方式编译时,函数调用注意事项
- 几种函数调用方式
- C++中函数调用时的三种参数传递方式详解
- java程序调用C、C++动态库的几种实现方式,即JNI的应用方式
- C++中函数调用时的三种参数传递方式
- 几种函数调用方式
- C++程序中不同的函数调用方式
- 函数声明的几种方式,函数声明与函数表达式的区别,函数调用的几种方式
- 标准C++中的几种强制类型转换方式比较说明
- c++中的几种函数调用约定
- 关于c++中调用exe的几种方式
- 几种函数调用方式
- 用C++读写EXCEL文件的几种方式比较
- 几种函数调用方式
- C++中函数调用的方式