-
一直以来,我们只是单纯的去运行执行 C 程序,并没有关心这个可执行文件里面包含着什么东西。
-
参考UNIX 环境高级编程 7.6,记录C程序的存储空间布局。
void test(void)
{
printf("This is test function
");
}
int main(void)
{
printf(" This is main function
");
return 0;
}
```c
看一下这个代码生成可执行文件的各个内存分布:
sbc_7109_454_pdk3@aplex:~/test/c_program$ gcc test.c -o test
sbc_7109_454_pdk3@aplex:~/test/c_program$ size test
text data bss dec hex filename
1229 552 8 1789 6fd test
然后,我们在里面加一个局部变量,全局变量:


在看一下局部静态变量:

-
栈和堆
在执行程序前,我们能看到的是上面的 非初始化数据段以及初始化数据段和正文段,在执行了程序后,我们还能看到栈和堆。
栈:自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次调用函数时,其返回地址以及调用者的环境信息,都存放在栈中。然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈,可以递归调用C函数,递归函数每次调用自身时,就使用一个新的栈帧,因此一个函数调用实例中的变量集不会影响另一个函数调用实例中的变量。
局部变量也是存放在栈区。
堆:动态内存分配。堆处于非初始化数据段和栈之间。
-
代码 test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test(void)
{
printf("This is test function
");
}
int test1 = 100;
int test2;
int main(void)
{
int a;
static int b = 100;
static int c;
char *test3;
test3 = (char *)malloc(sizeof(char) * 10);
int *pa = &a, *pb = &b, *pc = &c, *ptest1 = &test1, *ptest2 = &test2;
printf("桟:pa = %p
", pa); // 桟 stack
printf("堆:test3 = %p
", test3); // 堆 heap
printf("bss: ptest2 = %p
", ptest2); // 未初始化的数据区
printf("bss: pc = %p
", pc); // 未初始化的数据区 bss
printf("data: ptest1 = %p
", ptest1); // 初始化的数据区
printf("data: pb = %p
", pb); // 初始化的数据区
free(test3);
return 0;
}

-
空间分配如下图所示: