3.C++函数调用过程

1.函数中普通变量的内存分配问题

  • 当一个函数进行调用时,函数的形参、以及函数的局部变量都会在栈中被分配内存,而栈又分两种;
  1. 栈低不变,栈顶不断动态变化;
  2. 栈顶不变,栈低在动态变化;
#include <iostream>
using namespace  std;
void print()
{
int a=0,b=1,c=2;
cout<<"&a="<<reinterpret_cat<void*>(&a)<<endl;
cout<<"&b="<<reinterpret_cat<void*>(&b)<<endl;
cout<<"&c="<<reinterpret_cat<void*>(&c)<<endl;
}//reinterpret_cast运算符是用来处理无关类型之间的转换,它会产生一个新的值,这个值会有和原始参数有完全相同的比特位;
int main()
{
print();
return 0;
}

输出:
&a=0x7ffdded7a38c
&b=0x7ffdded7a390
&c=0x7ffdded7a394

  • 可以发现,abc地址依次升高,所以,在C++中函数调用过程中定义的局部变量是采用栈底不变,栈顶不断变换的内存栈 ,随着声明顺序,内存地址依次降低;

2.函数中数组变量的内存分配问题

  • 数组在分配时一次性分配整个数组的内存?
  • 数组中各个元素的地址分配顺序时怎样的?
#include <iostream>
using namespace std;
void print()
{
int a=0;int b=1;
int c=2;int arr[2];
cout<<"&a="<<reinterpret_cast<void*>(&a)<<endl;
cout<<"&b="<<reinterpret_cast<void*>(&b)<<endl;
cout<<"&c="<<reinterpret_cast<void*>(&c)<<endl;
cout<<"&arr[0]="<<reinterpret_cast<void*>(&arr)<<endl;
cout<<"&arr[1]"<<reinterpret_cast<void*>(&arr[1])<<endl;
}
int main()
{
print();
return 0;
}

输出:
&a=0x7fffb69b53e4
&b=0x7fffb69b53e8
&c=0x7fffb69b53ec
&arr[0]=0x7fffb69b53f0
&arr[1]0x7fffb69b53f4

在这里插入图片描述

3.函数调用堆栈的过程

#include<stdio.h>
int sum(int a,int b)
{
int tmp=0;
tmp =a+b;
return tmp;
}
int main()
{
int a=10;
int b=20;
int ret=0;
ret=sum(a,b);
printf("ret=%d\n",ret);
return 0;
}
  • 生成反汇编代码方式
    1.生成代码汇编后的二进制文件;<-- gcc -c -o sum.o
    2生成反汇编代码 : < ------ objdumo -d sum.o > sum.o.txt
  • 反汇编可执行二进制文件
gcc sum.c -g -o sum    //编译
objdump -S sum > sum.txt   //将在汇编代码中加入源文件代码

参考:函数调用堆栈的过程

时间紧张,日后补上,这里就看一下结论;

  • 整个函数的调用过程:
  1. 将调用方法的栈底地址入栈。——>push ebp;
  2. 让原本指向调用方栈低的ebp指向当前函数的栈底, ----> mov ebp,esp
  3. 给当前函数开辟栈帧;----> sub esp,44h
  4. 对开辟的栈帧进行初始化,初始化的大小不一定; ----->rep stos
  • 结论:
    1.函数的运行都是在栈上开辟内存的;
    2.栈是通过esp(栈顶指针)、ebp(栈底指针)两个指针来标识的;
    3.对于栈上的访问都是通过栈底指针的偏移来访问的;
    4.在call一个函数时,有两件事要做:先将调用的函数的下一行指令的地址压人栈中;再进行跳转;
    5.在函数调用时检查函数是否申明、函数名是否相同、函数的参数列表是否匹配、函数的返回值多大;
    (1)如果函数返回值<=4个字节,则返回值通过寄存器eax带回;
    (2)如果4<函数返回值<=8个字节,则返回值通过两个寄存器eax和edx带回,
    (3)如果函数返回值>8个字节,则返回值同产生的临时量带回;
    6.函数结束ret指令干了两件事:先出栈;再将出栈的值放到CPU的PC寄存器中,因为PC寄存器中永远存放的是下一次指令的地址;

函数调用过程参考1—反汇编代码
函数调用过程参考2
函数调用参考

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值