博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
stdcall, cdecl, pascal 区别(转载)
阅读量:5068 次
发布时间:2019-06-12

本文共 1750 字,大约阅读时间需要 5 分钟。

转载自:http://www.cnblogs.com/lidabo/archive/2012/11/21/2781484.html

stdcall, cdecl, pascal 区别

这三个参数都是告诉编译器参数的传递约定,参数的传递约定是指参数的传递顺序(从左到右还是从右到左)和由谁来恢复堆栈指针(调用者或者是被调用者),在 Win16下有两种约定: C 和 PASCAL。 

    C约定规定参数传递顺序是从右到左,即最右边的参数最先压栈,由调用者恢复堆栈指针。

    PASCAL约定和C约定正好相反,它规定参数是从左向右传递,由被调用者恢复堆栈。

    STDCALL是C约定和PASCAL约定的混合体,它规定参数的传递是从右到左, 恢复堆栈的工作交由被调用者完成。Win32只用STDCALL约定, 但除了一个特例, 即: wsprintf。

    __stdcall 这是一种函数调用方式。 __stdcall方式函数的参数压栈顺序从右到左,是Pascal 缺省调用方式,通常用于win32 API中,自己在退出时清空栈。

    __stdcall将参数压栈是按C语言的顺序(从右到左),但与C语言不同的是它是由被调用者将参数从栈中清除,所以它的编译文件比_cdecl小。

    __stdcall是Windows  API函数中默认的调用约定,VB、VFP等也采用这个约定。

    __cdecl是C语言采用的默认调用方法,对于传送参数的内存栈却是由调用者来维护的。实现可变参数的调用只能用该方法。是MFC的缺省调用参数。

    __fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上"@"前缀,在函数名后加上"@"和参数的字节数。

 

调用约定           压参数入栈顺序     把参数弹出栈者         函数修饰名(Calling convention)

-------------------------------------------------------------------------
__cdecl              右->左                     调用者                          _function   
__fastcall           右->左                     被调用者                       @function@nnn    
__stdcall            右->左                     被调用者                      _function@nnn
__pascal           左->右                      被调用者                      _function@nnn
-------------------------------------------------------------------------

 

以上几个关键词可在“windef.h”头文件中找到:

#define CALLBACK    __stdcall

#define WINAPI      __stdcall

#define WINAPIV     __cdecl

#define APIENTRY    WINAPI

#define APIPRIVATE  __stdcall

#define PASCAL      __stdcall

#define cdecl _cdecl

#ifndef CDECL#define CDECL _cdecl

#endif

几乎我们写的每一个WINDOWS API函数都是__stdcall类型的,为什么??

    首先,我们谈一下两者之间的区别:WINDOWS的函数调用时需要用到栈(STACK,一种先入后出的存储结构)。当函数调用完成后,栈需要清除,这里就是问题的关键,如何清除??如果我们的函数使用了__cdecl,那么栈的清除工作是由调用者,用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题,不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?答案是不能。如果使用__stdcall,上面的问题就解决了,函数自己解决清除工作。所以,在跨(开发)平台的调用中,我们都使用__stdcall(虽然有时是以WINAPI的样子出现)。那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的,被调用者事先无法知道参数的长度,事后的清除工作也无法正常的进行,因此,这种情况我们只能使用_cdecl。

转载于:https://www.cnblogs.com/sql4me/p/4478680.html

你可能感兴趣的文章
eggs
查看>>
一步步学习微软InfoPath2010和SP2010--第七章节--从SP列表和业务数据连接接收数据(4)--外部项目选取器和业务数据连接...
查看>>
oracle 报错ORA-12514: TNS:listener does not currently know of service requested in connec
查看>>
基于grunt构建的前端集成开发环境
查看>>
利用循环播放dataurl的视频来防止锁屏:NoSleep.js
查看>>
python3 生成器与迭代器
查看>>
java编写提升性能的代码
查看>>
Abstract Factory Pattern
查看>>
list 容器 排序函数.xml
查看>>
《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇03:暂停游戏》
查看>>
CPU,寄存器,一缓二缓.... RAM ROM 外部存储器等简介
查看>>
windows下编译FreeSwitch
查看>>
git .gitignore 文件不起作用
查看>>
Alan Turing的纪录片观后感
查看>>
c#自定义控件中的事件处理
查看>>
django Models 常用的字段和参数
查看>>
IOS--沙盒机制
查看>>
使用 JointCode.Shuttle 访问任意 AppDomain 的服务
查看>>
sqlite的坑
查看>>
digitalocean --- How To Install Apache Tomcat 8 on Ubuntu 16.04
查看>>