写了这么久的代码,你了解代码的执行过程吗?执行一行代码都干了些啥?简单的赋值到底是在干什么?来来,今天带大家入个门,修行就靠自己了。

不同的编译器编译后的执行效果不一样,这里以C语言编译结果为例。

我们先贴一段常规C代码


int m=10;
int main()
{
    int i=4;
    int j=5;
    m = fun(i,j);
    return 0;
}

int fun(int a,int b)
{
    int c = 0;
    c = a + b;
    return c;
}

计算机执行这段代码,都干了些啥?先来了解点常规知识

计算器的核心处理器是CPU,一个CPU有多个核心,一个核心里面包含有多种寄存器。

在这个案例中,主要会使用到 eip寄存器,ebp寄存器,esp寄存器。

eip寄存器:用于执行计算机指令的寄存器。如:mov,ret,add等。
ebp寄存器:指针始终指向栈顶端的寄存器,指针会根据栈的空间的变化而自动变化。
esp寄存器:指针指向栈底的寄存器,指针会随着作用域变化而变化。

程序启动时候,将会在内存中申请一个连续的内存地址,这个连续内存地址为栈区(这里的数据类型都是值类型)。 该栈区包含有:代码区,静态区,动态区。

代码区:用于存储代码的区域,主要用于执行计算机指令。
静态数据区:用于存储代码全局成员变量,可供不同方法使用的全局成员变量或其他全局对象。
动态数据区:用于存储代码动态执行过程中产生的数据。

初始栈区如下图所示:

程序启动时,将执行第一条指令,也就是进入到main函数。这个时候,esp寄存器所指向的地址将会在动态数据区保存起来,esp的指针同时也指向该地址。ebp指针也同样指向该地址,因为栈目前就只有一个数据。

紧接着,执行下面的两条赋值指令,此时,变量i和j将会在栈中做初始化。i和j的值会依次入栈。如下图所示:

紧接着要准备执行fun函数了。

执行fun函数,先将参数a,b的值进行入栈,入栈顺序是先入最右侧的参数,再入左侧的参数,此处先入b,再入a参数的值。

由于fun函数是有返回值的,所以栈区为返回值预留一个位置,此时还没有值。位置的大小由数据类型决定。

为了能够正确取到返回值,需要将返回值的地址记录下来,于是进行地址入栈操作。

返回值地址记录了以后,接下来要进入到fun函数的作用域了。为了确保函数可以跳出到先前作用域,并且后续能够清空无效的栈区,这里会记录作用域边界的指针地址,也就是前面提到的esp指向的指针地址。

后面的操作跟前面的步骤一致,将fun的变量c入栈。

后面紧接着执行a+b的指令,此时会将返回值传递给c。

这里要注意:a,b是属于main函数的作用域,它是从main函数传递给fun函数的参数值,也是属于“形参”的范畴,而i,j是属于实参。

因为a,b的指针位置都已经知道了,栈顶就是c的地址,在执行a + b指令后,将计算结果存储在C的位置。

因为代码区存储了函数的执行指令,ebp记录了作用域范围内的首地址,内部使用的变量会有相应的偏移量。根据首地址和偏移量就能找到他们的内存地址。

再把C的值赋值给fun函数的返回值,思路如同a+b。

到这里,fun函数的执行完了,接下来程序代码将返回到main函数中继续执行。

现在还需要做两件事:

1、恢复main函数栈。

2、跳转到fun函数的返回地址处继续执行给m赋值的操作。

现在开始恢复到main函数栈,根据前面记录的fun函数执行后的返回地址,ebp寄存器指针指向到返回地址(之前的地址从栈中移除),esp寄存器自动退位到该作用域的栈顶位置。

此时,过程如下图所示:

此时,fun函数执行的返回值需要赋值给m,此时会将fun函数的返回地址给到eip指令寄存器,并调用赋值指令。执行完后,fun函数执行返回地址将出栈。fun函数的作用域地址将会被回收。

a,b是形参,fun函数执行完成后,a,b已经不再需要了,从栈中移除。

剩下的就只有main函数的变量了,最后执行return 0的指令,执行完成后就将main函数的栈也清空了。这个时候的返回值,没有需要跳转的返回地址,就直接退出main函数了。

一个简单的函数执行过程就结束了。

以上内容,如果有错误还请在评论区指出。


本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/%E6%9C%80%E7%AE%80%E5%87%BD%E6%95%B0%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系