函数的调用方式
VC++下有三种函数调用方式,分别是:__cdecl 、 __stdcall 、__fastcal。第一种是C/C++默认的函数调用方式,如果不特殊指明用那种方式则默认使用__cdecl,而且只有第一种可以在不定参数的函数下使用,后面的方式指明所使用的函数必须是确定参数的,包括参数的个数和类型。下面就来详细介绍这三种调用方式之间的区别。
还是从例子开始:
刚开始是两个函数的定义,如下所示:
__stdcall调用:
8: void __stdcall ShowStd(int nNumber)
9: {//部分代码略,只看栈平衡的代码
10: printf("%d\r\n", nNumber);
11: }
0042B432 ret 4
__cdecl调用:
12: void __cdecl ShowCde(int nNumber)
13: {
14: printf("%d\r\n", nNumber);
15: }
0042B482 ret
这里可以看到__stdcall方式在函数结束时就进行栈平衡操作,ret 4相当于esp+=4。而__cdecl方式却没有,下面再来看main函数中的调用情况:
int main()
{
86: ShowStd(5);
0042B75E 6A 05 push 5
0042B760 E8 A9 D9 FF FF call ShowStd (42910Eh)
87: ShowCde(5);
0042B765 6A 05 push 5
0042B767 E8 38 DA FFFF call ShowCde (4291A4h)
0042B76C 83 C404 add esp,4
}
由函数调用可以看到__cdecl方式是在函数体外面进行栈平衡的,这就是这两个函数调用方式的不同之处,可以用来区分是哪种函数调用,但是也不能完全作为依据,只能做参考。
printf函数的参数不能确定,所以必须以_cdecl方式调用。在Debug版本下,连续的几个printf函数会在每次调用的时候分别进行栈平衡操作,但是在Release版本之下却并非如此,下面就举一个Release版本的例子(Debug版本和上面的调用一样,这里就不再举例):
C语言代码:
printf("Hello");
printf("World");
printf("C++");
printf("\r\n");
相应的反汇编代码:
.text:00401000 push offset aHello ; "Hello "
.text:0