C/C++调用约定
来源:互联网 发布:房产营销软件下载 编辑:程序博客网 时间:2024/05/16 15:10
C/C++函数调用约定
在编程中,一个函数完整的执行需要经过编译链接等多个过程,而在每个过程中编译器都需要为程序提供不同的服务,那么一个函数的调用执行到底需要几个过程呢?下面我们先通过一个函数栈帧的创建看看。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int Add(int left,int right)
{
return left +right;
}
int main()
{
int a, b;
int ret = 0;
scanf("%d%d", &a, &b);
ret = Add(a, b);
system("system");
return 0;
}
在这个程序中,我们来通过Add()函数的内部汇编代码来看看整个函数的执行过程:
下面我们用语言描述一下整个过程:
1. 为函数开辟空间
2. 初始化已开辟空间
3. 把函数参数压栈
4. 执行函数
5. 处理函数返回值
6. 对于第3步中压栈的那些寄存器,恢复它们原来的值
7. 根据不同的调用约定,清除第1步中压栈的参数,然后返回,或者先返回然后清除。
可以看到第6步是第3步的逆操作,而第7步是第1,2步的逆操作,在第3步中对函数的参数进行压栈,那么当参数个数多于一个时,编译器会按照什么顺序把参数压入栈的?而在第6、7步中又是怎么把堆栈恢复原装?这就引出了我们今天要讨论的题目——调用约定。
首先我们先来看看常用的几种调用约定:
在C语言中有: __cdecl、__stdcall、__fastcall、naked、__pascal
在C++中有: __cdecl、__stdcall、__fastcall、naked、__pascal、_thiscall
VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调用方式,在 DLL 导出函数中,为了跟Windows API 保持一致,建议使用 __stdcall 方式。
在VC中,可以设置默认的调用约定,设置路径为:Project à Properties à Configuration Properties à C/C++ à Advanced à call conversion
下面我们就来详细介绍一下这六种调用约定:
1、__cdecl
__cdecl调用约定又称为 C 调用约定,是 C/C++ 语言缺省的调用约定。参数按照从右至左的方式入栈,函数本身不清理栈,此工作由调用者负责,返回值在EAX中。由于由调用者清理栈,所以允许可变参数函数存在,如int sprintf(char* buffer,const char* format,...);。
2、__stdcall
__stdcall 很多时候被称为 pascal 调用约定。pascal 语言是早期很常见的一种教学用计算机程序设计语言,其语法严谨。参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。
3、__fastcall
顾名思义,__fastcall 的特点就是快,因为它通过 CPU 寄存器来传递参数。他用 eax 和 edx 传送前两个双字(DWORD)或更小的参数,剩下的参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在 EAX 中。
4、naked
naked 是一个很少见的调用约定,一般不建议使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是,你不能用return返回返回值,只能用插入汇编返回结果,此调用约定必须跟 __declspec 同时使用。例如定义一个求和程序,如__declspec(naked) int add(int a,int b);。
5、__pascal
这是 pascal 语言的调用约定,跟 __stdcall 一样,参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在eax中。VC 中已经废弃了这种调用方式,因此在写 VC 程序时,建议使用 __stdcall 代替。
6、__thiscall
这是 C++ 语言特有的一种调用方式,用于类成员函数的调用约定。如果参数确定,this 指针存放于 ecx 寄存器,函数自身清理堆栈;如果参数不确定,this指针在所有参数入栈后再入栈,调用者清理栈。__thiscall 不是关键字,程序员不能使用。参数按照从右至左的方式入栈。
- C函数调用约定
- c调用约定
- C/C++调用约定
- C调用约定
- C/C++调用约定
- c/c++调用约定
- C 调用约定和 C++调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C语言函数调用约定
- C/C++函数调用约定
- Java界面编程(GUI,AWT)
- 901-1000
- 1001-1100
- HDU 5961 传递 图论 BFS (2016CCPC 合肥 A题)
- Java EE基础知识1
- C/C++调用约定
- 1101-1200
- Spark-键值对RDD
- BZOJ 1588 营业额统计 Splay
- 弗罗贝尼乌斯范数(Frobenius norm)
- DDMS和TraceView的区别
- 多态、继承的概念
- Java创建多线程的三种方式
- 1201-1300