在C++中,为了允许操作符重载和函数重载,C++编译器往往按照某种规则改写每一个入口点的符号名,以便允许同一个名字(具有不同的参数类型或者是不同的作用域)有多个用法,而不会打破现有的基于C的链接器。这项技术通常被称为名称改编(Name Mangling)或者名称修饰(Name Decoration)。
__stdcall、__cdecl和__fastcall是C++中的三种函数调用约定,它们主要区别在于函数参数的传递方式和堆栈的清理方式。
__stdcall
在Windows系统的API开发中,__stdcall约定是默认的调用约定,并且是必须使用的。如果没有正确指定__stdcall约定,可能会导致无法正常调用API函数,导致程序运行异常或崩溃。
同时需要注意的是,__stdcall修饰符只能用于全局函数或静态成员函数,不能用于虚函数、内联函数或非静态成员函数等。
下面是一个使用__stdcall修饰符的示例:
int function (int a ,int b) //不加修饰就是C调用约定
int __stdcall function(int a,int b,...)//明确指出C调用约定
__stdcall int function(int a,int b,...)
__stdcall还有一个重要的特性,即指定了函数调用约定,用于指定函数在调用时如何从调用者传递参数以及将参数传递给被调用者和返回值。Windows API使用的是__stdcall约定,将参数从右至左推入堆栈中,由调用者恢复函数的堆栈。
__stdcall修饰符是一种用于兼容不同编译器和平台的函数修饰符,可以用于指定函数的参数传递和调用方式,并且应该合理使用函数定义和声明中。
__cdecl
如果需要显式指定一个函数使用__cdecl,调用约定可以使用__cdecl修饰符来声明该函数。例如:
int function (int a ,int b) //不加修饰就是C调用约定
int __cdecl function(int a,int b) //明确指出C调用约定
{
return a+b;
}
此时编译器会将该函数编译为使用__cdecl调用约定的函数。需要注意的是,通常情况下不需要使用__cdecl修饰符,除非有特殊的需求。
__fastcall
__fastcall是C++中的一种函数调用约定,用于指定函数参数的传递方式和寄存器的使用方式。它可以使函数调用更加高效。
使用__fastcall需要遵循以下几个步骤:
在函数声明或定义中使用__fastcall关键字指定函数调用约定。
例如:
int __fastcall myFunction(int a, int b,int c, int d);
按照指定的约定方式传递函数参数。__fastcall约定规定前两个整型或指针类型参数使用寄存器传递,其余参数使用堆栈传递。
例如:
int a = 1, b = 2, c = 3, d = 4;
int result = myFunction(a, b, c, d);
在上面的例子中,a和b会使用寄存器传递,c和d会使用堆栈传递。
注意:__fastcall约定只适用于x86架构的CPU,对于其他架构的CPU可能需要使用其他的函数调用约定。
总之,__fastcall可以使函数调用更加高效,但需要注意使用约定方式传递函数参数。
三个函数调用约定的区别
__stdcall:常见的函数调用约定,参数从右往左依次入栈,由被调用函数负责清理堆栈。在使用__stdcall约定时,函数的参数和返回值都会被压入堆栈中,堆栈的使用较大。
__cdecl:默认的函数调用约定,参数从右往左依次入栈,由调用方负责清理堆栈。在使用__cdecl约定时,函数的参数和返回值都会被压入堆栈中,堆栈的使用较大。
__fastcall:快速调用的函数调用约定,规定函数的前两个整型或指针类型参数使用寄存器传递,其余参数使用堆栈传递。在使用__fastcall约定时,函数的参数和返回值都会被压入堆栈中,但是由于使用了寄存器传递参数,因此可以减少堆栈的使用。