您的位置:首页 > 编程语言 > C语言/C++

C语言编程程序的内存如何布局

2018-01-24 14:42 246 查看
原文:https://www.2cto.com/kf/201604/497636.html

c语言中,每个变量和函数有两个属性:
数据类型
数据的存储类别


C语言中局部变量和全局变量变量的存储类别(
static
,
extern
,
auto
,
register
)


1. 从变量的作用域划分变量(即从
空间
)角度来分


1.全局变量


2.局部变量


2. 从变量值存在的时间或存储类别(即
生存期
)角度来分


2.1. 静态存储区


存放以下数据:
代码段(text)
只读数据段(rodata)
读写数据段(rwdata)
未初始化数据段(bbs)


静态存储区存放全部的全局变量, 这些变量将在链接之后产生, 程序执行完毕就释放, 程序执行的过程中它们占据固定的存储单元, 而不会动态的进行分配和释放


2.2. 动态存储区


存放以下数据:
函数形参
自动变量(未加static声明的局部变量)
函数调用时的现场保护和返回地址


对以上这些数据,在函数开始调用时分配动态存储空间,函数结束时释放这些空间。


3. 从用户内存空间角度分为三个部分


1. 程序区


?

2. 静态存储区


3. 动态存储区


4. 从C程序
运行时
又可分为以下存储区


1. 代码段 (Code | Text)

代码段由程序中执行的机器代码组成。在C语言中,程序语句进行编译后,形成机器代码。在执行程序的过程中,CPU的程序计数器指向代码段的每一条
机器代码
,并由处理器依次运行。


2. 只读数据段(ROData)


2.1 ROData介绍


只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。 只读数据段由程序中所使用的数据产生,该部分数据的特点是在运行中不需要改变,因此编译器会将该数据段放入只读的部分中。C语言中的
只读全局变量
只读局部变量
,程序中使用的
常量
等会
在编译时
放入
只读数据区
注意
:定义全局变量const
char a[100]={“ABCDEFG”};将生成大小为100个字节的只读数据区,并使用“ABCDEFG”初始化。如果定义为:const char a[ ]={“ABCDEFG”};则根据字符串长度生成8个字节的只读数据段(还有’\0’),
所以在只读数据段中,一般都需要做完全的初始化。


2.2 Example


?


3. 已初始化读写数据段(RW data)


3.1 RWData介绍


已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并具有初值,以供程序运行时读写。 全局变量全部存放在静态存储区,
在程序开始执行时给全局变量分配存储区
程序行完毕就释放
。在
程序执行过程中它们占据固定的存储单元
而不动态地进行分配和释放


全局变量

静态(static) 局部变量


3.2 Example


?


4. 未初始化数据段(BSS)


4.1 BSS介绍


未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。


4.1 Example


?


5. 堆(heap)


5.1 堆空间介绍


堆内存
只在程序运行时出现
,一般由程序员
分配
释放


在具有操作系统的情况下,如果
程序没有释放
操作系统
可能在
程序
(例如一个
进程
)
结束后回收内存



5.2 Example


?


6. 栈(stack)


6.1 栈空间介绍


栈内存
只在程序运行时出现
,在
函数内部使用的变量
函数的参数
以及
返回值
使用栈
空间, 栈空间由编译器自动分配和释放。
栈空间
动态开辟
回收
的。在函数调用过程中,如果
函数调用的层次比较多
,所需要的
栈空间也逐渐加大
对于
参数的传递
返回值
,如果使用
较大的结构体
,在
使用的栈空间也会比较大


6.2 栈区主要用于以下数据的存储

函数内部的动态变量 函数的参数 函数的返回值

6.3 Example


?
===================================华丽的分割线=========================


5. 4种局部变量和全局变量的存储类别(
static
,
extern
,
auto
,
register
)


5.1 Static


有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。

?
对静态局部变量的说明:


1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储空间,函数调用结束后即释放。

2)静态局部变量在编译时赋初值,即只赋初值一次;而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。

3)如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。


5.2 Extern


外部变量
即全局变量
)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字
extern
对该变量作“
外部变量声明
”。
表示该变量是一个已经定义的外部变量
。有了此声明,就可以从“
声明
”处起,
合法地使用该外部变量


?
说明:


在本程序文件的最后1行定义了外部变量A,B,但由于外部变量定义的位置在函数main之后,因此本来在main函数中不能引用外部变量A,B。现在我们在main函数中用extern对A和B进行“外部变量声明”,就可以从“声明”处起,合法地使用该外部变量A和B。


5.3 Auto


函数中的局部变量,如不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中
。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。这类局部变量称为
自动变量
。自动变量用关键字auto作存储类别的声明。

?
a是形参,b,c是自动变量,对c赋初值3。执行完f函数后,自动释放a,b,c所占的存储单元。

关键字auto可以省略,
auto不写则隐含定为“自动存储类别”,属于动态存储方式
。 占用
栈空间



5.4 Register


为了提高效率,C语言允许将局部变量得值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。

?
说明:


1)
只有局部自动变量和形式参数可以作为寄存器变量


2)一个计算机系统中的寄存器数目有限,
不能定义任意多个寄存器变量


3)
局部静态变量不能定义为寄存器变量



6. 总结

从变量的作用域(即从
空间
)角度来
,可以分为
全局变量
局部变量

从变量值存在的作时间(即
生存期
)角度来
,可以分为
静态存储
方式和
动态存储
方式。

代码段
只读数据段
读写数据段
未初始化数据段
属于
静态区域


静态区域
: 是指在程序运行期间分配固定的存储空间的方式

属于
动态区域


动态区域
: 是在程序运行期间根据需要进行动态的分配存储空间的方式。

代码段
只读数据段
读写数据段
在链接之后产生

未初始化数据段
在程序初始化的时候开辟
在程序的运行中分配和释放

C语言程序分为
映像
运行时
两种状态。
在编译-连接后形成的映像中
,将只包含
代码段(Text)
只读数据段(RO
Data)
读写数据段(RW
Data)
。 在
程序运行之前
,将动态生成未初始化数据段(
BSS
)
程序的运行时
还将动态形成
堆(Heap)
区域和
栈(Stack)
区域。一般来说,在静态的映像文件中,各个部分称之为
节(Section)
,而在运行时的各个部分称之为
段(Segment)
。如果不详细区分,可以统称为

C语言在
编译和连接后
,将生成
代码段
(Text)、只读数据段(
RO
Data
)和读写数据段(
RW Data
)。在
运行时
,除了以上三个区域外,还包括未初始化数据段(
BSS
)区域和堆(
Heap
)区域和栈(
Stack
)区域。


7. 一些实例

?
  读写数据段包含了忆初始化的全局变量 static char rw_1[ ]以及局部静态变量static rw_2[ ].其差别在于编绎时,是在函数内部使用的还是可以在整个文件中使用。对于rw_1[] 无论有无static 修饰,其都将被放置在读写数据区,只是能否被其它文件引用与否。对于后者就不一样了,它是局部静态变量,放置在读写数据区,如果没static修饰,其意义完全改变,它将会是开辟在栈空间的局部变量,而不是静态变量,在这里rw_1[],rw_2[]后没具体数值,表示静态区大小同后面字符串长度决定。

  对于未初始化数据区BSS_1[100]与BSS_2[100],其区别在于前者是全局变量,在所有文件中都可以使用;后者是局部变量,只在函数内部使用。未初始化数据段不设置后面的初始化数值,因此必须使用数值指定区域的大小,编绎器将根据大小设置BSS中需要增加的长度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: