Visual C++ 编译器参数传递和命名约定——关于__cdecl和__stdcall
来源:互联网 发布:linux系统分区 编辑:程序博客网 时间:2024/06/07 08:41
通过 Visual C++编译器,您可以为传递参数指定约定并返回函数和调用方之间的值。 并非所有支持的平台上都有所有约定,因此某些约定使用特定平台的实现。 在大多数情况下,忽略指定特定平台上不受支持约定的关键字或编译器开关,和使用平台默认约定。
在 x86 平台上,在通过时,所有参数扩展到 32 位。 回归值也扩展为 32 位,并且返回 EAX 寄存器,除了 8 字节结构返回 DEX:EAX 寄存器。 更大的结构在 EAX 寄存器返回,作为到隐藏的返回结构的指针。 参数从右向左被推入堆栈中。 不是 POD 的结构不会返回到寄存器中。
该编译器生成 prolog和 epilog 编码来保存和还原 ESI、 EDI、和 EBX EBP 寄存器,如果这些在函数中使用。
说明:当结构、联合或类从函数返回值时,该类型的所有定义需要相同,或者该过程可能会在运行时失败。
有关如何定义自己的prolog 函数和 epilog 代码的信息,请参见裸函数调用。有关以 x64 平台为目标的代码中的默认调用约定的信息,请参阅 x64调用约定概述。 有关针对 ARM 平台的代码中的调用约定问题的信息,请参阅 Visual C++ARM迁移的常见问题。
可视化 C/C++ 编译器支持以下调用约定。
关键字
“堆栈”清理
参数传递
__cdecl
调用方
将参数压入堆栈,按照相反的顺序(从右到左)
__clrcall
无
顺序加载参数到 CLR 表达式堆栈上(从左到右)。
stdcall
被调用方
将参数压入堆栈,按照相反的顺序(从右到左)
__fastcall
被调用方
存储在寄存器,然后推入堆栈
__thiscall
被调用方
压入堆栈:this 指针存储在 ECX 中
__vectorcall
被调用方
存储在寄存器,然后以相反顺序推入堆栈(从右到左)
__cdecl
__cdecl 是 C 和 C++ 程序的默认调用约定。 由于堆栈已有调用方清理,因此它可以执行 vararg 函数。 由于每个函数调用均要求包括堆栈清理代码,__cdecl 调用约定需比__stdcall 调用约定创建较大的可执行文件。 以下列表显示此调用约定的实现。
元素
实现
参数传递顺序
从右向左。
堆栈维护职责
调用函数在堆栈中弹出参数。
名称修饰约定
除了在导出使用 C 链接的 __cdecl 功能的情况下,下划线字符 (_) 都是名称的前缀。
用例转换约定
不执行任何大小写转换。
在 ARM 和 x64 处理器上,__cdecl 由编译器接受和忽略;在ARM 和 x64 体系结构上,按照约定,如果可能,变量将传入寄存器,且后面的参数在堆栈上传递。
将 __cdecl 修饰符放置在变量或者函数名称前面。 由于 C 命名和调用转换为默认,因此,只有当您指定 /Gv (vectorcall)、/Gz (stdcall) 或 /Gr (fastcall) 编译器选项时才需要使用 __cdecl。 /Gd 编译器选项强制 __cdecl 调用约定。
对于非静态函数类,如果函数是超行定义的,则调用约定修饰符不必在超行定义中指定。 用于非静态成员方法类,也就是说,假定声明时具有的泛型是指定的调用约定。 给定此类定义:
struct CMyClass {
void __cdecl mymethod();
};
如下:
void CMyClass::mymethod() { return; }
等效于此:
void __cdecl CMyClass::mymethod() { return;}
示例
在下面的示例中,将指示编译器使用 C 命名和调用 system 函数约定。
// Example of the __cdecl keyword on function
int __cdecl system(constchar *);
// Example of the __cdecl keyword on function pointer
typedef BOOL (__cdecl *funcname_ptr)(void * arg1,const char * arg2, DWORDflags, ...);
__stdcall
__stdcall 调用约定用来调用Win32 API 函数。 被调用方清理堆栈,因此,该编译器进行 vararg 函数 __cdecl。 使用此调用约定的函数需要一个函数原型。
return-type __stdcall function-name[(argument-list)]
以下列表显示此调用约定的实现。
元素
实现
参数传递顺序
从右向左。
参数传递约定
除非指针或引用类型通过,否则使用此值。
堆栈维护职责
被调用函数在堆栈中弹出自己的参数。
名称修饰约定
下划线 (_)作为名称的前缀。 该名称跟在后接函数列表的字节数(以十进制为单位)的符号 (@) 后。 因此,声明为 int func( int a, double b ) 的函数修饰如下所示:_func@12
用例转换约定
无
/Gz 编译器选项为所有没有用不同调用约定显式声明的函数指定 __stdcall。
使用 __stdcall 修饰符声明的函数与使用 __cdecl 声明的函数以相同的方式返回值。
在 ARM 和 x64 处理器上,__stdcall 由编译器接受并忽略;在ARM 和 x64 体系结构上,按照约定,如果可能,变量将传入寄存器,且后面的参数在堆栈上传递。
对于非静态函数类,如果函数是超行定义的,则调用约定修饰符不必在超行定义中指定。 用于非静态成员方法类,也就是说,假定声明时具有的泛型是指定的调用约定。 给定此类定义,
struct CMyClass {
void __stdcall mymethod();
};
this
void CMyClass::mymethod() { return; }
等效于此
void __stdcall CMyClass::mymethod() {return; }
示例
在下面的示例中,stdcall 的使用生成所有的作为标准调用的已处理的 WINAPI 函数类型:
//Example of the __stdcall keyword
#defineWINAPI __stdcall
//Example of the __stdcall keyword on function pointer
typedef BOOL (__stdcall *funcname_ptr)(void * arg1,const char * arg2, DWORD flags, ...);
参考文献:
http://msdn.microsoft.com/zh-cn/library/984x0h58.aspx
- Visual C++ 编译器参数传递和命名约定——关于__cdecl和__stdcall
- 带你玩转Visual Studio——调用约定__cdecl、__stdcall和__fastcall
- 带你玩转Visual Studio——调用约定__cdecl、__stdcall和__fastcall
- 关于__stdcall和__cdecl
- __stdcall和__cdecl调用约定及名称改编约定
- 调用约定(__stdcall and __cdecl)和修饰名(extern c)
- DLL中调用约定和名称修饰(__cdecl,__stdcall,__fastcall)
- DLL中调用约定和名称修饰(__cdecl,__stdcall,__fastcall)
- 关于函数调用方式`__stdcall`和`__cdecl`
- __cdecl,__stdcall和__fastcall
- __cdecl和__stdcall
- __stdcall和__cdecl
- __stdcall和__cdecl
- __cdecl和__stdcall
- __cdecl和__stdcall差别
- __cdecl和__stdcall区别
- __cdecl和__stdcall
- __stdcall、__cdecl和__fastcall
- 在eclipse中如何安装插件?
- 多态、动态类型和动态绑定
- MyEclipse集成SVN史上最简便方法
- 两列里不同数据的行筛选出来
- cocos2dx 3.0 ----- __Array
- Visual C++ 编译器参数传递和命名约定——关于__cdecl和__stdcall
- 消息队列
- UCOSII中的任务切换原理介绍
- 在red hat linux下安装oracle的相关问题
- 网络知识收集
- poj 1695 DP
- 浅谈Android应用性能之内存
- (8)ExtJS之form表单
- 能让你成为更优秀程序员的10个C语言资源