__stdcall、__cdcel、__fastcall、thiscall等关键字的作用

__stdcall、__cdcel、__fastcall、thiscall等关键字的作用

#include "stdafx.h"
#include <iostream>
using namespace std;

#if 0

__stdcall、__cdcel、__fastcall、thiscall等关键字的作用

相关概念:并不是所有的语言都支持_cdcel调用规则,但是都支持_stdcall调用规则, 
假如你用VC做了一个DLL, 导出了某些函数, 如果你想这个DLL被其他语言也能调用的话(如VB.DEPHI.PB..)
你的把他的调用约定声明为__stdcallwindows   api都是_stdcall调用规则,
函数调用约定确定一个程序如何实现一个函数调用及参数如何传递。在单一语言程序中,
调用约定几乎总是正确的,这是因为对所有模块总有一个缺省的约定并且头文件会负责
调用和被调用程序之间的一致性。在一个混合语言程序中,不同的语言不可能分享同一
个头文件。由于调用约定而产生的错误在编译时无法发现,直到程序在运行时(run - time)
实现函数调用时才出现并会立即导致应用程序崩溃。

__stdcall 的作用:__stdcall是一种调用约定方式,这样导出的dll可以被其他语言使用

__stdcall、__cdcel和__fastcall三者的区别:

1.调用协议常用场合
(1).__stdcall:Windows API默认的函数调用协议
(2).__cdecl:C / C++默认的函数调用协议
(3).__fastcall:适用于对性能要求较高的场合

2.函数参数入栈方式
(1).__stdcall:函数参数由右向左入栈
(2).__cdecl:函数参数由右向左入栈
(3).__fastcall:从左开始不大于4字节的参数放入CPU的ECX和EDX寄存器,其余参数从右向左入栈
注:__fastcall在寄存器中放入不大于4字节的参数,故性能较高,适用于需要高性能的场合

3.栈内数据清除方式
(1).__stdcall:函数调用结束后由被调用函数清除栈内数据  (被调用者)
(2).__cdecl:函数调用结束后由函数调用者清除栈内数据     (调用者)
(3).__fastcall:函数调用结束后由被调用函数清除栈内数据 (被调用者)
注1:不同编译器设定的栈结构不尽相同,跨开发平台时由函数调用者清除栈内数据不可行
注2:某些函数的参数是可变的,如printf函数,这样的函数只能由函数调用者清除栈内数据
注3:由调用者清除栈内数据时,每次调用都包含清除栈内数据的代码,故可执行文件较大

4.C语言编译器函数名称修饰规则
(1).__stdcall:编译后,函数名被修饰为“_functionname@number”
(2).__cdecl:编译后,函数名被修饰为“_functionname”
(3).__fastcall:编译后,函数名给修饰为“@functionname@nmuber”
注1:“functionname”为函数名,“number”为参数字节数
注2:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用

5.C++语言编译器函数名称修饰规则
(1).__stdcall:编译后,函数名被修饰为“ ? functionname@@YG******@Z”。
(2).__cdecl:编译后,函数名被修饰为“ ? functionname@@YA******@Z”。
(3).__fastcall:编译后,函数名被修饰为“ ? functionname@@YI******@Z”。
注1:“******”为函数返回值类型和参数类型表。
注2:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。
注3:C语言和C++语言间如果不进行特殊处理,也无法实现函数的互相调用。

6.thiscall仅仅应用于“C++”成员函数。this指针存放于CX寄存器,参数从右到左压
栈的维护者是被调用者,thiscall不是关键词,因此不能被程序员指定

7.naked call采用以上的调用约定时,如果必要的话,进入函数时编译器会产生代码
来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。
naked call不产生这样的代码。naked call不是类型修饰符,故必须和_declspec共同使用。

#endif 

猜你喜欢

转载自blog.csdn.net/SwordArcher/article/details/81476416
今日推荐