进程的内存布局如下图所示,栈是其中一块向下(低地址处)增长的内存。
栈的英文是stack,堆的英文是heap,很多人把stact翻译成堆栈,是不对的。
栈由栈帧组成
。当一个函数调用时,栈会为这个函数分配一个栈帧,用于存储函数的实参、局部变量、返回值,以及函数内调用函数时,当前函数的一些寄存器的相关信息(比如用于指向下一条指令的程序计数器)。
可以认为,一个栈帧存储一个函数。
当该函数调用结束后,栈帧会自动从栈上移去(这解释了局部变量的生存期问题)。
由于函数的嵌套,栈中可能有多个栈帧,此时,
最后分配的栈帧称为栈顶
,如下图所示。栈指针寄存器用于存储栈顶的地址,以跟踪栈顶。
下面,我们使用GDB查看一个实例的栈信息。实例程序gdbtest.cpp如下:
#include <stdio.h>
int square(int a, int b){
int ret = a*a + b*b;
return ret;
}
int doCalc(int num1, int num2){
int ret = square(num1, num2);
return ret;
}
int main(){
int param1 = 1;
int param2 = 2;
int result = doCalc(param1,param2);
printf("result is%d\n",result);
}
编译:g++ -g gdbtest.cpp
启动gdb:gdb a.out。
由源文件可知,main函数里面嵌套doCalc函数,doCalc函数又嵌套square函数,因此,这三个函数在栈中的分配如上图所示。在square函数中设置断点,程序停在断点后,使用backtrace命令,即可看到栈内容,如下所示:
(gdb) backtrace
#0 square (a=1, b=2) atgdbtest.cpp:6
#1 0x00000000004005e6 in doCalc(num1=1, num2=2) at gdbtest.cpp:10
#2 0x0000000000400613 in main ()at gdbtest.cpp:17
每一行前面的序号,就是栈帧在栈中的序号,#0表示栈顶,#1表示下一个栈帧,以此类推。使用frame 1,可以选择1号栈帧,使用info locals可以当前栈帧的局部变量:
(gdb) backtrace
#0 square (a=1, b=2) at gdbtest.cpp:6
#1 0x00000000004005e6 in doCalc (num1=1, num2=2) at gdbtest.cpp:10
#2 0x0000000000400613 in main () at gdbtest.cpp:17
(gdb) frame 1
#1 0x00000000004005e6 in doCalc (num1=1, num2=2) at gdbtest.cpp:10
10 int ret = square(num1, num2);
(gdb) info locals
ret = 0
(gdb)
进程的内存布局如下图所示,栈是其中一块向下(低地址处)增长的内存。
栈的英文是stack,堆的英文是heap,很多人把stact翻译成堆栈,是不对的。
栈由栈帧组成
。当一个函数调用时,栈会为这个函数分配一个栈帧,用于存储函数的实参、局部变量、返回值,以及函数内调用函数时,当前函数的一些寄存器的相关信息(比如用于指向下一条指令的程序计数器)。
可以认为,一个栈帧存储一个函数。
当该函数调用结束后,栈帧会自动从栈上移去(这解释了局部变量的生存期问题)。
由于函数的嵌套,栈中可能有多个栈帧,此时,
最后分配的栈帧称为栈顶
,如下图所示。栈指针寄存器用于存储栈顶的地址,以跟踪栈顶。
下面,我们使用GDB查看一个实例的栈信息。实例程序gdbtest.cpp如下:
#include <stdio.h>
int square(int a, int b){
int ret = a*a + b*b;
return ret;
}
int doCalc(int num1, int num2){
int ret = square(num1, num2);
return ret;
}
int main(){
int param1 = 1;
int param2 = 2;
int result = doCalc(param1,param2);
printf("result is%d\n",result);
}
编译:g++ -g gdbtest.cpp
启动gdb:gdb a.out。
由源文件可知,main函数里面嵌套doCalc函数,doCalc函数又嵌套square函数,因此,这三个函数在栈中的分配如上图所示。在square函数中设置断点,程序停在断点后,使用backtrace命令,即可看到栈内容,如下所示:
(gdb) backtrace
#0 square (a=1, b=2) atgdbtest.cpp:6
#1 0x00000000004005e6 in doCalc(num1=1, num2=2) at gdbtest.cpp:10
#2 0x0000000000400613 in main ()at gdbtest.cpp:17
每一行前面的序号,就是栈帧在栈中的序号,#0表示栈顶,#1表示下一个栈帧,以此类推。使用frame 1,可以选择1号栈帧,使用info locals可以当前栈帧的局部变量:
(gdb) backtrace
#0 square (a=1, b=2) at gdbtest.cpp:6
#1 0x00000000004005e6 in doCalc (num1=1, num2=2) at gdbtest.cpp:10
#2 0x0000000000400613 in main () at gdbtest.cpp:17
(gdb) frame 1
#1 0x00000000004005e6 in doCalc (num1=1, num2=2) at gdbtest.cpp:10
10 int ret = square(num1, num2);
(gdb) info locals
ret = 0
(gdb)