你是否在编译完成后关注过下面的信息
Program Size: Code=4348 RO-data=428 RW-data=36 ZI-data=2188
不知道的话可以猜猜
首先点击编译按键后,生成的是hex文件,单片机都是通过烧写hex文件来更新代码的,结合里面的关键词,因此这个“Program Size” 可能是跟hex文件有关。
没错,这行信息描述的就是hex文件的占用情况,我们来一项一项分析
先挑简单的:
code:不难理解,就是你最终编译完成的代码大小
但是剩下的都是什么鬼,好像从来没见到过,再猜一猜,程序运行除了代码还需要什么?
数据呗,因此不管后面三项的前缀是什么,后面的“xx-data”代表他们是数据,那么是啥数据呢?为什么还要分成三个类别?
那么这时候我么就可以回顾一下学习c语言了解到的知识:“内存分区”
首先明确几点:
1、我们单片机存储部分,由内到外分为cache、ram、rom。在刚上电的时候,ram里是没有数据的。
2、c语言中的“内存分区”中的内存,指的是ram,不是rom,结合1可以得出结论,单片机在启动后运行前,首先要将程序从rom搬运到ram中,不然没法运行的。
明确了上述几个点后,我们知道,单片机是需要将rom中的数据搬运到ram中的,因此我们可以借“内存分区”来找找有什么蛛丝马迹。从而判断为什么要给hex中的数据分类,以及每个类都是什么。
c语言内存分区,一共五个
地址从高到低依次是:
栈
堆
全局变量:分为初始化的(.data)和未初始化的(.bss)两个部分
常量:一些字符串,const修饰的全局变量
代码段
从上面可以看出,单片机运行需要搬运哪些数据,首先排除堆栈,因为栈里包含的都是局部变量,过程变量,都是随用随开辟,而堆是专门给编程人员开辟的自由空间,因此排除掉,
那么还剩下三个:全局变量(.data + .bss)、常量、代码段
这三个可以理解肯定是需要从rom中搬运了。我们再回头看一下编译完的文件分成哪几个部分来着?
那我们来一一对应一下,
code:应该是对应代码段
常量:应该是对应ro-data,猜测ro是read only的意思
剩下.data和.bss是对应什么呢?
.bss刚才上面介绍,是未初始化的全局变量,因此这个ZI-data ZI全称为Zero init(零初始化)可想而知,.bss应该是对应ZI-data了
而RW-data:read&write应该就是全局变量了。
因此,我们通过“前后夹击”的方式知道了这几个分区代表什么意思了,结合网上的相关文章可以得知,这几个分区就是这个意思
我们来总结一下各个 分区的含义
RO-data:只读数据
RW-data:初始化过的数据
ZI-data:没初始化过的数据
OK! 大功告成,
等等~,是不是还漏了什么,话说为什么要把数据分成这几个,变成一个区多方便
那么答案大概可以猜到就是,一个分区会不方便或者不安全
你想想,ZI-data的意思是什么?未初始化的变量。未初始化代表什么?也就是没有具体的数值,那么我们烧写到单片机rom中的hex文件是不是可以不用专门为ZI-data开辟空间,这样可以节省很大一部分的单片机rom。
那么还有两个分区呢?ro-data 和rw-data。
这可以说一下ro-data,ro是只读嘛,所以这一段他就相当于直接固化在内存中,这样带来一个好处就是固定错误比较方便,还有就是防止程序错误修改。
这也就是你看到常见讲keil输出编译信息的文章中,编译后的数据只保存RO-data和RW-data,没有ZI-data,而rom中三者(rw、ro、zi)都包括。
因此我们编译完的代码需要分区,而且需要分成上面这几个分区。
还有一些问题,等我搞清楚了再回来补上
· 编译后输出的文件中没有为ZI-data开辟空间,那么ZI-data信息以什么方式保存?
· 我只知道上电后 rom会加载成五个部分,那么是怎么加载的?有什么讲究?
· 单片机上电后走一个什么流程?单片机默认是再rom还是ram运行?