函数调用约定

函数调用约定:是对函数调用时如何传递参数的一种约定。

调用函数前要先把参数压入栈然后再传递给函数,栈就是定义在进程中的一段内存空间, 其大小被记录在PE头中,进程运行时确定栈内存的大小(与malloc/new动态分配内存不同)

函数执行完成后,栈中的参数不用处理
因为只是临时存储在栈中的值,清除会浪费CPU资源,直接下一次向栈中存入其他值自然覆盖就行了,而且栈的内存是固定的,所以不能也不用释放内存。

函数执行完毕之后,ESP值如何变化?
ESP的值要恢复到函数调用之前,这样可引用的栈大小才不会被缩减。如何处理ESP,就要用到函数调用约定。

调用者:调用函数的一方
被调用者:被调用的函数
例如,main函数中调用printf()函数,调用者为main(),被调用者为printf()。

主要函数调用约定

cdecl

调用者直接清理其压入栈的函数参数。主要在C语言中使用。

优点:可以向被调用函数传递长度可变的参数。这种长度可变的参数在其它调用约定中很难实现。

stdcall

常用于Win32 API,该方式由被调用者清理栈,C语言默认的函数调用方式为cdecl,若想要使用stdcall方式编译源码,只要使用_stdcall关键字就可以
示例代码:

#include<stdio.h>

int _stdcall add(int a,int b)
{
	return (a+b);
}

int main(int argc,char* argv[])
{
	return add(1,2);
}

优点:通过被调用者清理栈,和cdecl相比代码尺寸要小。

fastcall

与stdcall方式基本类似,但该方式通常会使用寄存器(而非栈内存)去传递需要传递给函数的部分参数(前2个),若某函数有4个参数,则前两个参数分别使用ECX、EDX寄存器传递
优点:速度快,实现对函数的快速调用
缺点:可能会增加系统开销,还可能需要备份ECX和EDX中的数据。

三种调用约定对比图

函数调用约定

上一篇:Delphi stdCall意义


下一篇:jna StdCallCallback 回调问题查证