1. 代码区 – 存放代码/函数,只读区
2. 全局区 – 保存全局变量,读写区
3. BSS段 – 未初始化的全局变量,BSS段在main执行前会自动清0
4. 栈区 – 存局部变量,包括函数形参,栈区的内存是自动分配自动回收的
5. 堆区 – 程序员自己管理的区域,malloc/ free操作的都是堆区。
6. 只读常量区 – 存放字符串常量和const修饰的全局变量。
注:只读常量区和代码区合并在一起。
上面的这种划分在很多文档中都有看到,这里我不想再一一介绍。只想说一下其中的误解和陷阱,本文讲以一下几部分展开:
1)变量前缀和储存位置
2)为什么要有bss段,全局变量未初始化到底放哪?
3)linux察看内存分配的map文件
一,变量前缀 和 储存位置:
这部分帮助大家回顾const, static,auto,全局,局部等变量常量的储存位置。
首先看下面的一个小程序:
const int i2 = 10;
int * p2 = &i2;
*p2 = 200;
printf("%d\n",i2);
大家猜猜输出的结果。是不是会出现编译错误或者运行时错误?
答案是:输出200。运行时有警告:非常指针指向常变量。
再看下面的一段代码:
1 #include
2 int main()
3 {
4 char *a="asdaasasda";
5 char *p = a;
6 *p = 'z';
7 printf("%s\n", a);
8 return 0;
9 }
运行时会提示:段保护错误。
1 #include
2 char *f()
3 {
4 char *t = "happy!";
5 return t;
6 }
7 int main()
8 {
9 char *a="asdaasasda";
10 //char *p = a;
11 //*p = 'z';
12 //printf("%s\n", a);
13 printf("%s\n",f());
14 return 0;
15 }
执行结果:happy!
这样我们可以得出结论:多种声明方式容易搞混,而其实只有生存周期和存储位置的对应关系是不变的。长周期变量:必然存在全局区和常量区,而临时变量都存在栈区。反之亦然:
存在全局区的和常量区的都是长周期变量,栈区都是临时变量。
隐式声明:char *str = "XXXX";其实是static const的。或者可以理解在编译阶段字符串被抽取出来随文件一起保存。
二,可爱的BSS段:
BSS段的全称是什么?很多人知道bss段是存储未初始化全局变量的,可是没有去想为什么系统要单独开辟一个区去存未初始化全局变量?bss区有什么特殊的地方,使得他适合去存储未初始化的全局变量?下面为大家解决这些问题:
BSS(Block Started by Symbol),如果大家对汇编有所了解,肯定知道block的概念。我们在C代码中定义的变量都是按照block存的。数组名就是block首地址的symbol。一般都是这样的格式:
AAA dw 0,1,2.....
AAA后面没有冒号,在运行时如果用AAA做相对寻址,其单元大小都是dw。这就是汇编里对应数组的结构:block。
BSS段中有很多数组?对还是错?其实by symbol就是告诉我们有很多数组symbol,但是后面的具体数据并不在bss中。那么这就像一张列出数组symbols的表格了。那么为什么要搞这么一张表,不能直接存数据么?你可以想象如果数组很大,怎么把这么多数据写在二进制文件中。那将会使得文件很大。最关键的是,一会我们会看到,开始分配4G内存的时候,全局变量区的大小是定死了的!你放太大的数组会使得出现多个内存数据不连续片断。而局部变量不存在这个问题,栈是向上增长的,理论上没有容量上限。参看下图:
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |