【C++内存管理】浅析C++中函数调用时的内存分配-函数调用过程中其他函数相关的内存分布

来源:互联网 发布:linux deamon 编辑:程序博客网 时间:2024/04/29 06:24
#include<iostream>using namespace std;void print(){cout<<"hello world"<<endl;} void test(){int arr[1];arr[2]=(int)print;} int main(){test();return 0;}

以上代码,运行结果为:

[Hyman@Hyman-PC cplus]$ g++ array.cpp [Hyman@Hyman-PC cplus]$ ./a.out hello world

问题:为什么上述代码中根本没有调用print函数的语句,但是却打印出来了hello world的?


    在上一篇文章《浅析C++中函数调用时的内存分配-函数局部变量的内存分配》中,最后留下了一个很有意思的问题,在代码中没有任何一个语句调用了print()函数,结果print()函数却被执行了。现在就对该问题进行分析:

  首先,我们先说明下C++中内存结构的分布,如下图所示:




    整个内存从低地址到高地址一次分为代码段、数据区、堆区、栈区、和命令行参数、系统变量存储区。

    代码段负责存放程序的各种指令,数据区主要存放全局数据、静态数据,而堆区是进行内存分配的地方,栈区是在进行局部变量存放的地方(栈顶是动态变化的),最上面的是存放系统变量和命令行参数等等。

    我们再看一下在执行一个函数时,函数怎么在栈区分配地址:


    在函数执行过程中,首先在栈中放入函数调用前的各个寄存器的执行状态,因为函数结束时需要将函数寄存器的值回到原位,然后存入形参(这点还有争议,和我之前看过的资料不一样,资料上说形参应该存到局部变量前面,但是我通过做实验并查看相关汇编代码,实际形参的存储位置应该如图),然后存入函数的返回地址(所谓返回地址就是函数结束后的下一条语句地址),然后是函数返回值(为返回值预留空间),最后是函数的局部变量。

    在这个例子中,我们定义了一个只含有一个元素的整形数组arr[1],然后数组越界把arr[2]存放了函数print的地址。

    先看此时的内存分布(只看局部变量部分):


     从图中可以看到,我们将print的函数地址放入了本该是函数返回地址的地方,这就导致test函数一结束就调用了print函数,也就打印出了”hello world”,这也就是在我们看来为什么没有调用函数print函数的语句,print函数却被调用的原因了。




0 0
原创粉丝点击