C语言程序的内存布局

来源:互联网 发布:聚合色情直播软件 编辑:程序博客网 时间:2024/05/16 12:56

    我们做C语言中这么多年,都知道这样一句话,C语言代码形成可执行程序,需要经过编译->汇编->链接三个阶段。背都背熟了,但是到底啥意思,每一步都会产生一些什么东西,很多人都不是太了解。今天就详细的来说说这个问题:

   先看下图,在这个图中,我详细的描述了,整个过程及中间的一些步骤:

layer

     代码段,只读数据段,读写数据段,未初始化数据段属于静态区域。栈和堆属于动态区域。代码段,只读数据段和读写数据段将在连接之后产生,未初始化数据段将在程序初始化的时候开辟,而堆和栈将在程序的运行中分配和释放。

ccodelayer

    C语言程序分为映像和运行两种状态。在编译连接后形成的映像中,将只包含代码段,只读数据段和读写数据段。在程序运行之前,将动态生成未初始化数据段,在程序的运行时还将动态形成堆和栈区域。

    而上面的程序呢, 最终都会转化为内存中的都会放置在内存中运行,程序的几个段,最终也几个区域。C语言可执行程序的内存布局如下图所示:

内存布局

    在内存中,从低地址到高地址,依次是只读段,读写段,未初始化段,堆,栈段。这只是一种内存分布,并没有考虑到实际系统的情况。在实际的系统中,程序有载入和运行两个概念。嵌入式系统有两种内存,一种是可以固化只读的内存(如ROM,Nor Flash),另一种是易失的可读写的内存(SRAM和SDRAM)。程序中的各个段也有需要固化和需要读写的。程序中的各个段必须载入到内存的恰当位置,程序才可以运行。C语言中各部分需要固化和可写的情况如下表:

需要固化?

需要可写?

代码是否只读数据是否读写数据是是未初始化数据否是堆否是栈否是

     一般情况下,经过编译后的程序存储在Flash或这硬盘中,在运行时需要将程序加载到RAM中。嵌入式系统的Nor Flash和硬盘还有一定的差别,在硬盘的程序必须加载到RAM中才可以运行,但是在Nor Flash中的程序可以通过XIP的方式运行。

说了这么多,说了最后可执行文件的结构分配,说了存储方式,这里我还是忍不住说一些static的话题了:

     静态变量说明符是static。 静态变量是静态存储方式,但是属于静态存储方式的量不一定就是静态变量。 例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由static加以定义后才能成为静态外部变量,或称静态全局变量。
1)静态局部变量:它在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。

2)允许对构造类型静态局部量赋初值  例如数组,若未赋以初值,则由系统自动赋以0值。

3)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。 根据静态局部变量的特点, 可以 看出它是一种生存期为整个源程序的量。虽然离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。 因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。

4)静态全局变量:全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局 变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此 可以避免在其它源文件中引起错误。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。

当一个源程序由多个源文件组成时,C语言根据函数能否被其它源文件中的函数调用,将函数分为内部函数和外部函数:

1)内部函数(又称静态函数):在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。定义一个内部函数,只需在函数类型前再加一个“static”关键字即可
正因为此,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。
使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。

2 )外部函数:在定义函数时,如果没有加关键字“static”,或冠以关键字“extern”,表示此函数是外部函数:
[extern]  函数类型  函数名(函数参数表)
{……}
调用外部函数时,需要对其进行说明:
[extern]  函数类型  函数名(参数类型表)[,函数名2(参数类型表2)……]; 

 


原创粉丝点击