A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© xqlyn123 中级黑马   /  2015-10-28 11:23  /  973 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

进程中内存空间的划分:

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内存的时候,全局变量区的大小是定死了的!你放太大的数组会使得出现多个内存数据不连续片断。而局部变量不存在这个问题,栈是向上增长的,理论上没有容量上限。参看下图:




4 个回复

倒序浏览
p495416980 来自手机 中级黑马 2015-10-28 12:40:13
沙发
代码学好高深啊
回复 使用道具 举报
oc学起来真的挺难啊
回复 使用道具 举报
bss 完全没看懂 , 不过例1种的 结果楼主确定看文章的时候自己测试过了?
为什么我的到的结果和你说的不同;
int main()
{
        const int num = 0;
        int *p = #
        *p = 1;//num修改失败
        printf("num值 == %d\n*p的值 p == %d \n",num,*p);
        printf("num的地址===%p\np的地址=== %p\n",&num ,p);

          return 0;
}

打印结果
num值 == 0
*p的值  == 1
num的地址===0x7fff5fbff74c
p的地址=== 0x7fff5fbff74c
经过测试认为例1然并卵
一个内存地址出现两个值,变量被多次定义;
造成的结果未知,请楼下的同学求证。
回复 使用道具 举报
一时没看懂
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马