概述
1.栈 --由编译器自动分配释放,如局部变量。
2. 堆 --般由程序员分配释放,由程序员释放,如c中的malloc和free函数,和c++中的new和delete操作符。
3. 全局区(静态区) --全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束释放。
4.常量区。字符串常量放与此处,程序结束自动释放
5.程序代码区 存放程序的二进制代码
代码:
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456 在常量区,p3在栈上。
static int c = 0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456");
//123456 放在常量区,编译器可能会将它与p3所指向的"123456"优化成一块。
}
程序运行时内存的大致分布
+------------------+ 内存低端
| 代码段 |
|------------------|
| 数据段 |
|------------------|
| 堆 栈 |
+------------------+ 内存高端
这些区(数据结构)在编译之后的映像和运行时的两种结构
编程语言的的经典对立之一就是代码和数据的区别。代码和数据的区别也可认为是运行时和编译时的界限,编译器的绝大部分工作和翻译代码有关;必要的数据存储管理的绝大部分都在运行时进行。
编译之后的映像
下面以GCC编译器得到的a.out文件展开说明:
a.out:assembler output(汇编程序输出),但是,他不是汇编程序输出,而是链接器输出,这个名字曾被解释为:“新程序就绪,准备执行”它是链接器输出文件,它是一种二进制文件,存放的二进制是有规律的。
编译生成的目标文件和链接生成的可执行文件(本人的相关博文)都有不同的格式,但是它们都由段(segment)构成,段是二进制文件的简单区域,存放某种特定类型相关的所有信息。
段的感性认识,引入汇编程序:
汇编系统预定义的段名
l .text @代码段
l .data @初始化数据段 .data Read-write initialized longdata.
l .bss @未初始化数据段
l .sdata @ .sdata Read-write initialized short data.
l .sbss @
简化段伪指令 | 功 能 | 注释 |
.CODE [段名] | 创建一个代码段 | 段名为可选项,如不给出段名,则采用默认段名。对于多个代码段的模型,则应为每个代码段指定段名。 |
.DATA | 创建一个数据段 | 段名是:_DATA |
.DATA? | 创建无初值变量的数据段 | 段名是:_BSS |
.FARDATA [段名] | 建立有初值的远调用数据段 | 可指定段名,如不指定,则将以FAR_DATA命名。 |
.FARDATA? [段名] | 建立无初值的远调用数据段 | 可指定段名,如不指定,则将以FAR_BSS命名。 |
.CONST | 建立只读的常量数据段 | 段名是:CONST |
.STACK [大小] | 创建一个堆栈段并指定堆栈段大小 | 段名是:stack。如不指定堆栈段大小,则缺省值为1KB |
接着谈a.out二进制文件的分布,下面是其示意图:
a.out magic number:比如宏定义,#defineMAX_NUM 100
文本段(The text segment )包含程序的指令,链接器把指令直接从文件拷贝到内存中,以后就用管他,因为一般情况下下,文本区域是不会改变的,不论是大小还是内容。
数据段(The data segment)包含经过初始化的全局变量和静态变量以及他们的值。BSS段存放全局或静态的尚未初始化的数据变量,大小可从可执行文件中得到,然后链接器得到这个大小的内存块。包含数据段和BSS段的一般统称为数据区。这是因为,操作系统中,段是一块连续地址,所以相邻的段被结合。一般来讲,数据段在任何进程中都是最大的段。
堆栈段(The stack segment)上图显示了一个即将执行的进程的内存布局,我们仍然需要一些存储空间,用于存放局部变量,临时数据,传递到函数中的参数等等(local variables, temporaries, parameter passing in function calls,)。
Unmapped:位于虚拟地址空间的最低部分,它未被映射到程序中有用的部分,访问它是非法的,因为即使它位于地址空间内,但未给它分配真实的物理地址空间。
如果程序中还使用了共享库,进程的地址空间:
上面是编译时,C运行时对a.out的操作
运行时阶段,下面主要讲堆栈段的变化
The Stack Segment 堆栈段:
堆栈段包含一种单一的数据结构:堆栈。
堆栈为函数内部声明的局部变量提供存储空间。
函数调用的时候,堆栈存储相关的一些维护信息。这些信息被称为堆栈结构(stack frame)也叫做过程活动记录(precedure activation record)稍后讨论。
堆栈也可以作为临时存储区,有时候进程需要一些临时存储空间,比如执行一个复杂的计算时,可以把结果压到堆栈中。
值得一提的是:除了递归调用之外,堆栈并非必须。
以函数的调用为例:
c运行时系统在他自己的地址空间内如何管理程序的呢?这里做一个简单的讨论。
c语言自动提供一种用于函数调用的功能:称作调用链( keepingtrack of the call chain)记录了哪些函数调用哪些函数,以及return执行后,控制将返回什么地方。
解决这个问题的经典机制就是堆栈中的过程活动记录,每一个函数调用都会产生一个过程记录。其实它就是一种数据结构,记录调用后返回调用点需要的全部信息。
如下图就是一个过程活动记录的结构,不同的编译器会有所差别,但目的都是记录调用后返回调用点的信息。
下面展示递归调用过程:
C语言在编译和连接后,将生成代码段(Text)、只读数据段(RO Data)和读写数据段(RW Data)。在运行时,除了以上三个区域外,还包括未初始化数据段(BSS)区域和堆(Heap)区域和栈(Stack)区域。
最后
以上就是长情乌龟为你收集整理的C中变量存储区、程序编译后的映像和运行时的段分析的全部内容,希望文章能够帮你解决C中变量存储区、程序编译后的映像和运行时的段分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复