原帖 http://blog.sina.com.cn/s/blog_6b7c56870100l8rf.html

__cdecl   __fastcall与   __stdcall

调用约定:  
__cdecl   __fastcall与   __stdcall,三者都是调用约定(Calling   convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以及产生函数修饰名的方法。

1、__stdcall调用约定:函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,

2、_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。注意:对于可变参数的成员函数,始终使用__cdecl的转换方式。

3、__fastcall调用约定:它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。

4、thiscall仅仅应用于 "C++ "成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

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

调用约定可以通过工程设置:Setting...\C/C++   \Code   Generation项进行选择,缺省状态为__cdecl。

名字修饰约定:

1、修饰名(Decoration   name): "C "或者 "C++ "函数在内部(编译和链接)通过修饰名识别  
2、C编译时函数名修饰约定规则:  
__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个 "@ "符号和其参数的字节数,格式为_functionname@number,例如   :function(int   a,   int   b),其修饰名为:_function@8  
__cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_functionname。  
__fastcall调用约定在输出函数名前加上一个 "@ "符号,后面也是一个 "@ "符号和其参数的字节数,格式为@functionname@number。

3、C++编译时函数名修饰约定规则:  
__stdcall调用约定:  
1)、以 "? "标识函数名的开始,后跟函数名;  
2)、函数名后面以 "@@YG "标识参数表的开始,后跟参数表;  
3)、参数表以代号表示:  
X--void   ,  
D--char,  
E--unsigned   char,  
F--short,  
H--int,  
I--unsigned   int,  
J--long,  
K--unsigned   long,  
M--float,  
N--double,  
_N--bool,  
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以 "0 "代替,一个 "0 "代表一次重复;  
4)、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;  
5)、参数表后以 "@Z "标识整个名字的结束,如果该函数无参数,则以 "Z "标识结束。  
其格式为 "?functionname@@YG*****@Z "或 "?functionname@@YG*XZ ",例如  
int   Test1(char   *var1,unsigned   long)-----“?Test1@@YGHPADK@Z”  
void   Test2()   -----“?Test2@@YGXXZ”

__cdecl调用约定:  
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的 "@@YG "变为 "@@YA "。  
__fastcall调用约定:  
规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的 "@@YG "变为 "@@YI "。  
VC++对函数的省缺声明是 "__cedcl ",将只能被C/C++调用.

注意:  
1、_beginthread需要__cdecl的线程函数地址,_beginthreadex和CreateThread需要__stdcall的线程函数地址。

2、一般WIN32的函数都是__stdcall。而且在Windef.h中有如下的定义:  
#define   CALLBACK   __stdcall  
#define   WINAPI    __stdcall

3、extern   "C "   _declspec(dllexport)   int   __cdecl   Add(int   a,   int   b);  
typedef   int   (__cdecl*FunPointer)(int   a,   int   b);  
修饰符的书写顺序如上。

4、extern   "C "的作用:如果Add(int   a,   int   b)是在c语言编译器编译,而在c++文件使用,则需要在c++文件中声明:extern   "C "   Add(int   a,   int   b),因为c编译器和c++编译器对函数名的解释不一样(c++编译器解释函数名的时候要考虑函数参数,这样是了方便函数重载,而在c语言中不存在函数重载的问题),使用extern   "C ",实质就是告诉c++编译器,该函数是c库里面的函数。如果不使用extern   "C "则会出现链接错误。  
一般象如下使用:  
#ifdef   _cplusplus  
#define   EXTERN_C   extern   "C "  
#else  
#define   EXTERN_C   extern  
#endif

#ifdef   _cplusplus  
extern   "C "{  
#endif  
EXTERN_C   int   func(int   a,   int   b);  
#ifdef   _cplusplus  
}  
#endif

5、MFC提供了一些宏,可以使用AFX_EXT_CLASS来代替__declspec(DLLexport),并修饰类名,从而导出类,AFX_API_EXPORT来修饰函数,AFX_DATA_EXPORT来修饰变量  
AFX_CLASS_IMPORT:__declspec(DLLexport)  
AFX_API_IMPORT:__declspec(DLLexport)  
AFX_DATA_IMPORT:__declspec(DLLexport)  
AFX_CLASS_EXPORT:__declspec(DLLexport)  
AFX_API_EXPORT:__declspec(DLLexport)  
AFX_DATA_EXPORT:__declspec(DLLexport)  
AFX_EXT_CLASS:#ifdef   _AFXEXT  
AFX_CLASS_EXPORT  
#else  
AFX_CLASS_IMPORT

6、DLLMain负责初始化(Initialization)和结束(Termination)工作,每当一个新的进程或者该进程的新的线程访问DLL时,或者访问DLL的每一个进程或者线程不再使用DLL或者结束时,都会调用DLLMain。但是,使用TerminateProcess或TerminateThread结束进程或者线程,不会调用DLLMain。

7、一个DLL在内存中只有一个实例  
DLL程序和调用其输出函数的程序的关系:  
1)、DLL与进程、线程之间的关系  
DLL模块被映射到调用它的进程的虚拟地址空间。  
DLL使用的内存从调用进程的虚拟地址空间分配,只能被该进程的线程所访问。  
DLL的句柄可以被调用进程使用;调用进程的句柄可以被DLL使用。  
DLLDLL可以有自己的数据段,但没有自己的堆栈,使用调用进程的栈,与调用它的应用程序相同的堆栈模式。

2)、关于共享数据段  
DLL定义的全局变量可以被调用进程访问;DLL可以访问调用进程的全局数据。使用同一DLL的每一个进程都有自己的DLL全局变量实例。如果多个线程并发访问同一变量,则需要使用同步机制;对一个DLL的变量,如果希望每个使用DLL的线程都有自己的值,则应该使用线程局部存储(TLS,Thread   Local   Strorage)。

(转)__cdecl __fastcall与 __stdcall的更多相关文章

  1. 调用约定__cdecl __fastcall与__stdcall

    __cdecl __fastcall与__stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数弹出栈,3)以 ...

  2. __cdecl 、__fastcall、__stdcall

    调用约定: __cdecl __fastcall与 __stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数 ...

  3. 【C/C++开发】__stdcall,__cdecl,__fastcall的区别

    __stdcall和__cdecl的区别 __stdcall和__cdecl是两种函数名字修饰.(注意是连续的两个下划线) Windows上 windows上不管是C还是C++,默认使用的都是__st ...

  4. __stdcall,__cdecl,__fastcall的区别

    __stdcall,__cdecl,__fastcall的区别 标签: dll编译器pascalclassimportinitialization 2009-12-09 15:07 10472人阅读  ...

  5. 闲话__stdcall, __cdecl, __fastcall出现的历史背景以及各自解决的问题

    可以认为最先由微软搞出来了__stdcall, 其实就是和WINAPI的声明是一样的,入栈顺序是从右到左,函数返回时,会进行出栈操作. PASCAL语言是非常古老的编程语言,在C语言之前,因此在当时的 ...

  6. __stdcall,__cdecl,__fastcall,_stdcall,_cdecl,_fastcall 区别简介[转]

    今天写线程函数时,发现msdn中对ThreadProc的定义有要求: DWORD WINAPI ThreadProc(LPVOID lpParameter);   不解为什么要用WINAPI宏定义,查 ...

  7. __cdecl __stdcall __fastcall之函数调用约定讲解

    首先讲解一下栈帧的概念: 从逻辑上讲,栈帧就是一个函数执行的环境:函数参数.函数的局部变量.函数执行完后返回到哪里等等. 实现上有硬件方式和软件方式(有些体系不支持硬件栈) 首先应该明白,栈是从高地址 ...

  8. C++调用约定和名字约定

    C++调用约定和名字约定 转自http://www.cppblog.com/mzty/archive/2007/04/20/22349.html 调用约定:__cdecl __fastcall与 __ ...

  9. C/C++ Learning

    目录 1. C/C++中的关键字2. C/C++中的标识符3. 编译选项MD(d).MT(d)编译选项的区别4. C++类模板.函数模板5. C++修饰符6. 调用约定7. 错误处理8. 环境表 9. ...

随机推荐

  1. 块级格式化上下文(block formatting context)

    在CSS2.1中,有三种定位方案--普通流.浮动和绝对定位: 普通流:元素按照先后位置自上而下布局,inline元素水平排列,直到行被占满后换行,block元素则被渲染为完整的一行,除非指定,所有元素 ...

  2. python学习心得第二章

    python基础 1.关于python编码的问题. python的编码现在主要是两种版本python2.7和python3.5 python2.7默认的是ascii码进行编译,我们可以采用 # -*- ...

  3. log4net 记录日志到sqlserver

    参考:http://blog.csdn.net/niuyongjie/article/details/5777625 demo

  4. Storm-隔离调度器

    这个版本的亮点是新的“隔离调度器”,使得在一些拓扑中分享集群变得简单和安全.隔离调度程序允许您指定哪些拓扑应该“孤立”, 这意味着它们运行在集群中的一组专用的机器,没有其他的拓扑将运行.这些孤立的拓扑 ...

  5. machine leanring 笔记 vectorization

    the summation of the product of two terms can be expressed as the product of two vectors ps.  surf   ...

  6. layer弹出层不居中解决方案

    layer弹出层不居中解决方案 代码头中加入以下代码即可 <!doctype html>

  7. wcf用svcutil导出泛型的元数据

    D:\aaa>svcutil net.tcp://192.168.1.110:44444/TradingsService.svc/mex /ct:System.Collections.Gener ...

  8. struts2配置文件中Action中的各属性的含义

    StrutsApacheBeanJSPServlet attribute:      这个属性用来指定ActionForm保存到指定上下文时所使用的属性名.如果不指定attribute属性的值,将使用 ...

  9. Linux下Git和GitHub使用方法总结

    来源:Linux下Git和GitHub使用方法总结 1 Linux下Git和GitHub环境的搭建 第一步: 安装Git,使用命令 “sudo apt-get install git” 第二步: 到G ...

  10. POJ 3624 Charm Bracelet(01背包)

    Charm Bracelet Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 34532   Accepted: 15301 ...