【C/C++】总结常用的函数调用约定
一、函数调用的基本步骤
函数调用大致包括以下几个步骤。
(1)参数入栈:将参数从右向左依次压入系统栈中。
(2)返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。
(3)代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。
(4)栈帧调整:具体包括:
保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)。
将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部)。
给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶)。
二、函数调用约定:
调用约定的声明
参数入栈顺序
恢复栈平衡的位置
__cdecl
右→左
母函数
__fastcall
右→左
子函数
__stdcall
右→左
子函数
三、具体的表现
(1) __cdecl
函数本身不清理堆栈,调用者负责清理堆栈。由于这种变化,C调用约定允许函数的参数的个数是不固定的
(2) __fastcall
函数的第一个和第二个DWORD参数(或者尺寸更小的)通过ecx和edx传递,其他参数通过从右向左的顺序压栈
被调用函数清理堆栈
(3) __stdcall
参数从右向左压入堆栈
函数自身修改堆栈
四、VC下的表现
在VC的工程设置中可以设置函数调用方式,从表现可以看出明显的差别。
(1)如果设置成__cdecl*,那么对于下面的代码,汇编表现为:
00402692 push 8
00402694 push 5
00402696 push 3
00402698 call @ILT+275(GetNum) (00401118)
0040269D add esp,0Ch
(2)如果设置成__stdcall,那么对于下面的代码,汇编表现为:
00402692 push 8
00402694 push 5
00402696 push 3
00402698 call @ILT+280(GetNum) (0040111d)
(3)如果设置成__fastcall,那么对于下面的代码,汇编表现为:
00402692 push 8
00402694 mov
相关文档:
Boss说,要看OpenGL,看了快一个月,总算出了个像样的东西,用C写了个3D迷宫,
虽然只有350行
代码,不过边学边写,足足写了一周时间,还是小有成就感的,活活活!
&n ......
作者:王姗姗,华清远见嵌入式学院讲师。
在嵌入式开发中,作为底层开发者,更看重的是C语言的编程能力,但作为应用程序的开发者,我想学习C++还是有必要的。你只有在了解了C++的特性,从本质上看到它与C的区别才能坚定你认识学习它的决心。我不是专家,但是从我学习的历程上来看,学习C++还是有需要的,不论你做QT ......
随机生成整数,然后算出正负零
void getrand(int *a, int m)
{
int i;
srand(time(NULL));
for (i=0; i<m; i++)
{
a = rand()-rand();
}
}
int main(int argc, char* argv[])
{
  ......