一、引言
C语言中函数调用返回是一种很常见的形式,比如main函数调用了函数A,函数A又调用了函数B。那么函数调用过程中发生了什么,调用结束又是怎么返回到正确位置的。最近读了一些相关的资料,但书上得来终觉浅,今天就动手验证下书上的小例子,并写个博客记录下这个过程。
二、理论知识
1、进程的虚拟地址空间
有一道很经典的面试题,是问程序中各元素在内存中的分布。比如全局变量(已初始化、未初始化)、局部变量、静态变量等,在进程地址空间的什么段?或者直接问程序BSS段/栈空间/堆空间是什么,保存什么内容等。没有接触过这一块的肯定是一脸懵圈。
2、栈帧结构
栈的增长方向是从高地址到低地址的。函数调用时,会按照下图所示的方式保存栈帧信息。
三、实验过程
实验小程序源自参考文献1,本文在自己的Linux系统上做了验证。
测试环境:Ubuntu 18.04
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#define MAX (1UL << 29)
typedef unsigned long long u64;
typedef unsigned int u32;
u32 max_addend = MAX;
u64 sum_till_max(u32 n)
{
u64 sum;
n++;
sum = n;
if (n < max_addend)
sum += sum_till_max(n);
return sum;
}
int main(int argc, char** argv)
{
u64 sum = 0;
if((argc ==2) && (isdigit(*argv[1])))
max_addend = strtoul(argv[1], NULL,0);
if (max_addend >MAX || max_addend == 0)
{
fprintf(stderr, "Invalid number is specified\n");
return 1;
}
sum = sum_till_max(0);
printf("sum(0..%u) = %llu\n", max_addend, sum);
return 0;
}
四、参考文献
1、Debug Hacks中文版 -- 深入调试的技术和工具,电子工业出版社 2、文中图片来自网络,详细出处未知