C 程序在内存中的布局 [李园7舍_404]

原创 2013年12月02日 15:40:26

笔记题目比较高级,相信还有很多地方没有笔记清楚,主要是理思路类型,为具体抽象出C程序的每个部分与内存之间的关系图,也没有找到相关书籍查看到内存每个区域(静态区(代码段,只读(代码,数据),读写段),常量区,堆,栈)的具体分布及大小。路漫漫,继续进步吧。要是有本相关的书籍看看实在是好极了。

 

1 硬件平台

软件的运行基于操作系统,操作系统基于特定的硬件结构。

 

一个硬件平台包含“处理器(CPU)”、“系统内存”、“输入、输出设备”,组成每个部分的硬件结构也都比较复杂。处理器与它们的联系依靠“控制总线”、“地址总线”及“数据总线”实现。如下图所示:

 

由图可见,处理器(processor)和内存(system memory只是硬件平台的一部分。

 

2 程序的存储

 

(1) 内存与其它概念的区别

主要与寄存器,硬盘等外部存储器区别。

 

[1] 寄存器

寄存器是为了解决访问内存数据的复杂性和耗时性而被集成在处理器内的存储单元。处理器内(以IA-32为例)包含“通用寄存器”、“段寄存器”、“指令指针寄存器”、“浮点数据寄存器”、“控制寄存器”、“调试寄存器”、“标志寄存器”。

 

[2]硬盘

硬盘是计算机的外部存储器,是计算机上常见的CDE盘。用来保存各种类型的文件(如操作系统及操作系统的安装包)。硬盘不是内存。

 

[3]内存

内存是计算机的内部存储器,也叫做主存储器。是硬件平台的一个重要部分,其作用是用于暂时存放CPU中的运算数据以及与硬盘等外部存储器交换的数据

 

内存一般采用半导体存储单元,包括随机存储器(RAM),只读存储器(ROM),以及高速缓存(CACHE)。只不过RAM是其中最重要的存储器。计算机裸机自带的程序存储在内存中的ROM部分,应用程序运行时被载入到RAM中(所有的应用程序只有被载入到内存中后才能运行,如word安装包中的可执行文件要被载入内存中后才能按照word源代码指令运行,从而才有呈现在用户面前的word交互界面)。所以跟用户打交道的多为RAM。

 

ROM

由于ROM不会因为掉电而丢失其中存储的内容,内存中的ROM部分主要用来存储计算机的固定程序和数据,如BIOS。在装操作系统之前就可以开机接入BIOS界面中。由厂家往内存中的ROM部分烧录BIOS固定程序。但随着ROM的发展,依据ROM的子系列的新功能,BIOS也不是完全的不可改写,可以通过特殊方法将BIOS升级即重新向ROM中载入新版本的BIOS

 

RAM

对于应用程序如对于一个C语言程序来说,通常所说的内存就是指RAM[ ROM不可更改,由厂家设定,一般不与ROM交道 ],此段内存具有随机读写的特性。当然随着时间的流逝,科学的进步,现在的高档内存条都是采用RAM的子系列。

一个存在硬盘上的可执行文件经双击后其内数据就会被载入内存中,从而使可执行文件开始运行。此时计算机一但关机后,载入到内存中的可执行文件数据就会丢失。在计算机开机后,还需要重新双击可执行文件载入各种数据到内存中从头开始运行。

 

CACHE

RAM由于容量大、寻址系统繁多、读写电路复杂等原因,造成了内存的工作速度大大低于CPU的工作速度,直接影响了计算机的性能。为了解决内存与CPU工作速度上的矛盾,计算机专家在CPU和内存之间增设一级容量不大、但速度很高的高速缓冲存储器(Cache)。Cache通常由静态存储器(SRAM)构成。Cache中存放常用的程序和数据,当CPU访问这些程序和数据时,首先从高速缓存中查找,如果所需程序和数据不在Cache中,则到内存中读取数据,同时将数据写到Cache中。采用Cache可以提高系统的运行速度。

 

(2)程序的存储

对于应用程序执行被载入内存中时,是被载入到内存中的RAM部分。RAM由静态区和动态区组成。静态区分为只读数据区,初始化数据区,未初始化数据区。动态区分为堆(heap)和栈(stack)。可执行程序运行被载入内存中时,会将对应的部分存储到相应的内存模块中去。

 

[1] 静态内存区

静态内存主要用来存储“程序代码”及“数据”。

 

最终的可执行文件的代码部分会被存储在RAM中的某区域,存储指令的内存区域可将其称为代码段。代码段的指令由CS值存储基址,由指令指针寄存器指向下一条要取的指令。

 

在静态区中存储的数据主要指自动全局变量和静态变量。在C语言中,经初始化的全局变量和静态变量存储在静态区的一块区域中(将其称为数据段),未经初始化的全局变量和静态变量存储在静态区的另一块内存中(可将其称之为BSSBSS是英文Block Started by Symbol的简称,表示此种变量不在可执行文件中占用内存,用变量名作占位符记录此类型变量需要多少内存空间,系统将其初始化为0)。

 

对于静态局部变量,对局部变量加了static关键字后就改变了局部变量的存储方式。静态局部变量就不会再存储在栈上而是被存储在RAM中的静态区。

 

[2] 动态内存区

动态内存主要是在程序运行时且运行完分配动态内存的指令后动态内存才被分配。

 

对于来说,栈专门用来存非静态的局部变量和调用子函数时传递给子函数的实参。当非静态局部变量的生存期完后,栈内存也随之被系统回收。

 

对于来说,程序代码中有动态分配堆内存的函数(malloc/new)出现才有可能分配堆空间。并使用完堆内存后要用释放动态内存函数(free/delete)释放。即堆空间的分配和回收都是通过特定的代码实现。不管是分配还是释放环节,稍有不慎就会有内存泄露的危险。

 

[3] 常量区

就算是没有这个区域也可以这么看。可以将程序中突如其来的常量的存储区域称作常量区

 

[4] 程序

常量区和栈

#include <stdio.h>

char *mm_address();
char *stack_address();

int main(void)
{
        char *p = NULL;

        p       = mm_address();
        if(p){
                printf("mm address content: %s\n", p);
                p       = NULL;
        }

        p       = stack_address();
        if(p){
                printf("stack address content: %s\n", p);
                p       = NULL;
        }
        return 0;
}

//Return const mm address
char *mm_address()
{
        char *pC = "Hello World!\n";
        return pC;
}

//Retrun stack address
char *stack_address()
{
        char ar[] = "Hello World!\n";
        return ar;
}

 

编译并执行程序得到如下结果:

  • mm_address()函数能将字符串的地址返回给main函数中的p。在main程序中p所指的地址内还有正确的内容,说明“char *pC = "Hello World!\n";”中的字符串常量绝对不是存在了栈上。这样的字符串常量就被存在RAM的常量区。从程序执行结果可知,常量区数据的生命期至少不必main函数小,因为在main函数中字符串常量的内存还没有被释放掉。
  • stack_address()能够将字符串常量的地址返回给main函数中的p(p不为空)。但输出的是乱码。说明p所指内存的内容已经不存在。其实“char ar[] = "Hello World!\n";”语句是在栈上分配了以ar为名(首)的连续空间。等子函数运行完毕后,曾经存储字符串的占空间已经被回收。故而输出乱码。

堆和栈

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
        char *p;
        p       = NULL;

        p       = (char *)malloc(sizeof(char) * 10);
        if(p){
                *(p + 1)        = 'h';
                printf("the seconde byte content: %c\n", *(p+1));
        }

        if(p){
                free(p);
                p       = NULL;
        }
        return 0;
}
  • 程序运行到“char *p;”语句时,由于p为局部变量,p指针变量的内存在栈上
  • p       = (char *)malloc(sizeof(char) * 10);”语句欲分配大小为10字节的堆空间,分配成功后堆空间的首地址由p存储。堆空间的首地址不容弄掉。
  • 接下来往堆空间的第二个字节内存入’h’字符并将其打印出来,这些都是操作堆空间的行为。
  • 若堆空间分配成功后,手动将其释放掉。free(p)只是表示将堆空间回收,但p原本指向堆空间的值还存在,故而需要将p重新赋值为NULL,以避免使用野指针。

 

其它

对于其它前辈所标识的程序中的何种数据位于RAM中的哪个区,在不需要高度把握整个程序的运行情况下,似乎作用不是很大。

#include <stdio.h>
#include <stdlib.h>

int a = 0; //全局初始化区  
char *p1; //全局未初始化区  

int main(void)  
{  
	int b;// 栈  
	char s[] = "abc"; //栈  
	char *p2; //栈  
	char *p3 = "123456"; //"123456/0"在常量区,p3在栈上。  
	static int c =0; //全局(静态)初始化区  
	p1 = (char *)malloc(10);  
	p2 = (char *)malloc(20);  //分配得来得10和20字节的区域就在堆区。  
	strcpy(p1, "123456"); //123456/0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。  
}  


 

不禁猜之,内存硬件设计者肯定将内存划分了区域。如存储引导程序BIOS的ROM地址范围为0xyyyyyyyy ~ 0xzzzzzzzz。RAM代码段的地址范围为0xmmmmmmmm ~ 0xnnnnnnnn……清楚内存每个区域的范围,也就更加深入的了解了内存,可以直接对内存编写代码(不知道危险与否)。也知道了每个区域的内存大小,也就知道每种类型的数据最多能够定义多少,对编写程序实在是有帮助,尤其是对编写到嵌入式、单片机之类的程序。大师一样。继续探知。

 

此次笔记记录完毕。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

C语言数据在内存中的存储类别 [李园7舍_404]

探究C语言不同数据类型在内存中的存储很有意思,也是学习c语言时的难点。1的内容推进2的理解,含各变量的小特性哦。   1.程序存储区域 程序(可执行文件)进行存储时分为三个区域:代码段,数据段,...

C自定义函数的可变参数列表实现 Windows APIS目录遍历程序 [李园7舍_404]

The  C Programming Language例子笔记一。 The C Programming Language例子笔记二(本来应包含解析声明部分)见堆及堆分配。 1可变参数列表函数实现...

51 下载程序到单片机内 [李园7舍_404]

大三,matlab+嵌入式+程序员培养。从此需要坚持对单片机的学习。我会记录我在学习中的点点滴滴。 此文主要记录下载目标程序到单片机内的步骤。 1.安装下载软件 一般在买单片机的时候厂家会附加一张光盘...

matlab 绘制系统的单位阶跃响应曲线 并编写程序求峰值时间 超调量 [李园7舍_404]

1 内容 已知典型二阶系统的传递函数为                               其中 wn=2,阻尼比 分别为0.2,0.4,0.6,0.8,1,2时系统的单位阶跃响应曲线(绘制...

C 语言栈内存无法向父函数传递地址问题 [李园7舍_404]

当一个程序执行时,需要用一定的内存空间用与存放程序执行中使用到的各种数据。按内存空间分配方式的不同,一个程序所使用的内存区域可以分为静态内存和动态内存。在程序开始运行时由系统分配的内存称为静态内存,在...

51单片机程序执行流程(STARTUP.A51) [李园7舍_404]

keil 版本:uVision 4         单片机是没有上操作系统的东西,在keil中编写的代码都是裸机代码,深入编写裸机代码有助于了解硬件的特性。       若不是硬件特性已定的情况...

51定时器中断程序编写 [李园7舍_404]

上篇笔记记录到51单片机的中断允许寄存器、定时器/计数器工作方式寄存器(TMOD)、定时器/计数器控制寄存器(TCON)各位的作用。这些寄存器都是用来为编写定时器中断程序编写的初始化部分而服务的。然后...

matlab 编写M文件(函数) [李园7舍_404]

matlab的命令编辑窗口(Command Window)界面主要是用来调用系统命令、调用自定义函数(m文件里定义的函数)或编写一些较小的代码。在遇到需要用到比较多的代码才能摆平的需求时,在命令编辑窗...

51 机器周期 时钟周期 晶振频率 定时器初值计算 [李园7舍_404]

背景:51单片机引出的概念。   1 机器周期         在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。例如,取指令、存储器读、存储器写等,这每一...

2014深圳吉祥腾达校园招聘 [李园7舍_404]

深圳吉祥腾达公司在重庆的招聘地点在重庆邮电大学及重庆大学。   招聘的流程为宣讲会-->收简历(对参加笔试的环节放得比较松,如果场地允许只要参加宣讲会的都可以进入笔试)-->笔试(笔试结果当晚就会...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C 程序在内存中的布局 [李园7舍_404]
举报原因:
原因补充:

(最多只允许输入30个字)