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 语言栈内存无法向父函数传递地址问题 [李园7舍_404]

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

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

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

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

51 下载hex文件到单片机失败的解决方案 [李园7舍_404]

1.  第一次写hex文件按照“下载程序到单片机”的步骤成功下载。把程序内容深化了一些之后竟发觉hex文件不能下载到单片机内,出现以下的错误提示: Chinese:正在尝试与 MCU/单片机 握手连接...

C指针和堆空间 [李园7舍_404]

相关笔记:C指针和堆空间、C malloc()实际分配空间大小。 0 堆内存的在计算机内存中的形式 根据《The C Programming language》推测得到堆内存,图中的Hea...

keil编辑界面代码风格,字体,颜色设置 [李园7舍_404]

用keil软件写了一些非常简单的C语言控制程序。发现在写代码的时候,字体,代码颜色,缩进都给我的感觉都不是很好。于是便想重新设置一下编辑界面对代码所支持的风格。那么在keil的哪个地方去设置这些属性呢...

51 数码管动态显示 [李园7舍_404]

首先根据位选与段选理念(数码管静态显示一文)编写程序去控制不同数码管显示不同的数字。根据程序控制需要,在调试程序的过程中明白需要了解我们所要的控制对象(数码管)的一些特性。由于我自己拥有的这个单片机非...

51 Keil语句延迟时间的精确计算 [李园7舍_404]

一、   软件模拟运行速度与硬件对应 我们首先要找到单片机的晶振为多大(一般在配套的使用说明书中有标识或者直接在实验板上面看,实验板上面标识的不是很明显),如图所示左下角标识。        ...

2014深圳锐明视讯校园招聘 [李园7舍_404]

好几天前的笔试。今天去九龙坡面试了一趟。遇上辅导员找咱还三方协议,虽然是悄悄的拿的,但就是不想还回去。深圳锐明视讯的宣讲会流程为:宣讲会(1小时左右)-->笔试(1小时半),然后过两三天的时间部分同学...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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