今天在C#调用C++ DLL的时候出现了一些问题,后来追查了下去,原来是函数的调用约定出了问题。
调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变和由谁来处理堆栈等问题。不同的语言定义了不同的调用约定。
在C++中,因为重载的原因,所以对函数的命名方式和普通C语言并不一致,该方式称为名字改编。为了支持跨语言调用,特此出现双方协商的调用约定,以保证跨语言接口调用的成功。
约定一:__cdecl
__cdecl是C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参 数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的 函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。(函数调用处清栈)
下面将通过一个具体实例来分析__cdecl约定:
在VC++中新建一个Win32 Console工程,命名为cdecl。其代码如下:
int __cdecl Add(int a, int b); //函数声明
void main()
{
Add(1,2); //函数调用
}
int __cdecl Add(int a, int b) //函数实现
{
return (a + b);
}
函数调用处反汇编代码如下:
;Add(1,2);
push 2 ;参数从右到左入栈,先压入2
push 1 ;压入1
call @ILT+0(Add) (00401005) ;调用函数实现
add esp,8 ;由函数调用清栈
约定二:__stdcall
__stdcall调用约定用于调用