内存区域划分

image.png

入栈顺序

函数参数入栈顺序 - 自右向左

函数参数的入栈顺序和具体编译器的实现有关。有些参数是从左向右入栈,如:Pascal语言从左到右入栈(不支持变参),被调用者清栈;有些语言还可以通过修饰符进行指定,如:Visual C++;但是C语言(cdecl)采用自右向左的方式入栈,调用者清栈。
这是因为自右向左入栈顺序的好处就是可以动态的变化参数个数。通过堆栈分析可知,自左向右入栈方式中,前面的参数会被压入栈底。除非知道参数个数,否则无法通过栈指针的相对位移求得左边的参数。这样就无法实现可变参数。因此,C语言采用自右向左入栈顺序,主要是因为实现可变长参数形式(如:printf函数)。可变长参数主要通过第一个定参数来确定参数列表,所以自右向左入栈后,函数调用时栈顶指针指向的就是参数列表的第一个确定参数,这样就可以了。

局部变量的入栈顺序

跟编译器有关,大多数是 先声明的先入栈

gcc stack.c -g -o stack -fno-stack-pprotector //没有栈溢出保护机制下的编译

在没有栈溢出保护机制下编译时,所有局部变量按系统为局部变量申请内存中栈空间的顺序,即:先申请哪个变量,哪个先入栈,正向的。也就是说,编译器给变量空间的申请是直接按照变量申请顺序执行的。
在有栈溢出保护机制下编译时,入栈顺序有所改变,先按照类型划分,再按照定义变量的先后顺序划分,即:char型先申请,int类型后申请(与编译器溢出保护时的规定相关);然后栈空间的申请顺序与代码中变量定义顺序相反(后定义的先入栈)

变量出入栈规则

  • 任何出栈的元素后面出栈的元素必须满足以下三点:
  • 在原序列中相对位置比它小的,必须是逆序;
  • 在原序列中相对位置比它大的,顺序没有要求;
  • 以上两点可以间插进行。