C /C++开发中,程序编译没有问题,但连接的时候报告函数不存在,或程序编译和连接都没有错误,但只要调用库中的函数就会出现堆栈异常等现象。上述现象出如今C和C++的代码混合使用的状况下或在C++程序中使用第三方库(非C++语言开发)的状况下,缘由是函数调用约定(Calling Convention)和函数名修饰(Decorated Name)规则致使的。函数调用约定决定函数参数入栈的顺序,以及由调用者函数仍是被调用函数负责清除栈中的参数等问题,而函数名修饰规则决定编译器使用何种名字修饰方式来区分不一样的函数,若是函数之间的调用约定不匹配或者名字修饰不匹配就会产生以上的问题。
C++语言中的函数调用约定主要针对三个问题:
A、函数参数的入栈顺序
B、清理栈的主体(负责清理栈的主体:函数自身仍是调用函数者)
C、函数名称重整
调用约定主要是指函数被调用的方式,C++语言的函数调用约定主要有stdcall,fastcall,pascal,cdecl,thiscall等约定。
在C++中,为了容许操做符重载和函数重载,C++编译器一般按照某种规则改写每个入口点的符号名,以便容许同一个名字(具备不一样的参数类型或者是不一样的做用域)有多个用法,而不会打破现有的基于C的连接器。这项技术一般被称为名称改编(Name Mangling)或者名称修饰(Name Decoration)。C++编译器厂商一般选择本身的名称修饰方案。程序员
__stdcall
是StandardCall的缩写,是C++的标准调用方式。__stdcall
调用约定的规则以下:
A、全部参数从右到左依次入栈,若是是调用类成员的话,最后一个入栈的是this指针。
B、被调用函数自动清理堆栈,返回值在EAX。
C、函数修饰名约定:VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。ide
__cdecl
是C DECLaration的缩写(declaration,声明),表示C语言默认的函数调用方法。__cdecl
调用约定规则以下:
A、全部参数从右到左依次入栈
B、全部参数由调用者清除,称为手动清栈。返回值在EAX中
C、函数修饰名约定:VC将函数编译后会在函数名前面加上下划线前缀
因为由调用者清理栈,因此容许可变参数函数存在,如int sprintf(char buffer,const char format,...)。函数
__fastcall
是快速调用约定,经过寄存器来传送参数。__fastcall
调用约定的规则以下:
A、用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送
B、被调用函数在返回前清理传送参数的内存栈 ,返回值在EAX中
C、函数修饰名约定:VC将函数编译后会在函数名前面加上"@"前缀,在函数名后加上"@"和参数的字节数 。学习
thiscall是惟一一个不能明确指明的函数修饰符,thiscall只能用于C++类成员函数的调用,同时thiscall也是C++成员函数缺省的调用约定。因为成员函数调用还有一个this指针,所以必须特殊处理。
thiscall调用约定以下:
A、采用桟传递参数,参数从右向左入栈。若是参数个数肯定,this指针经过ECX传递给被调用者;若是参数个数不肯定,this指针在全部参数压栈后被压入堆栈。
B、对参数个数不定的,调用者清理堆栈,不然由被调函数清理堆栈
thiscall 不是关键字,程序员不能使用。this
__pascal
语言的调用约定,跟 __stdcall
同样,参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。VC 中已经废弃,建议使用 stdcall 代替。指针