野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 20204|回复: 9

变量的存储布局

[复制链接]
发表于 2013-5-13 19:09:13 | 显示全部楼层 |阅读模式

Q群中总会有人会问各种不同的问题,而很多问题很适合其他人参考了,故把它粘贴上来,以供参考:



我们编写程序时,各个变量是如何保存在内存中的呢?
一个进程运行时,所占用的内存,可以分为如下几个部分:
    1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。
    2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS释放。
    3、全局变量、静态变量:初始化的全局变量和静态变量放在一块区域,未初始化的全局变量和和未初始化的静态变量在相邻的的另一块区域。程序结束后由系统自动释放。
    4、文字常量:常量字符串就是存放在这里的,程序结束后由系统释放。
    5、程序代码:存放函数体的二进制代码。



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


常见的错误例子
void main()   
{   
    char *p="abcde";       //.rodata
    char a[]="abcde";      //.data
    p[1]='m';                  //错误,修改字符串常量
    a[1]='m';                  //正确,修改元素
}






回复

使用道具 举报

 楼主| 发表于 2013-5-13 19:10:45 | 显示全部楼层
ARM中的RO、RW和ZI DATA
用keil编译时,经常会出现这样的提示:

Code是代码占用的空间,RO-data是 Read Only 只读常量的大小,如const型,RW-data是(Read Write) 初始化了的可读写变量的大小,ZI-data是(Zero Initialize) 没有初始化的可读写变量的大小。ZI-data不会被算做代码里因为不会被初始化。
简单的说就是在烧写的时候是FLASH中的被占用的空间为:Code+RO Data+RW Data
程序运行的时候,芯片内部RAM使用的空间为: RW Data + ZI Data


   
ARM程序(指在ARM系统中正在执行的程序,而非保存在ROM中的bin文件)的组成
一个ARM程序包含3部分:RO段,RW段和ZI段
RO是程序中的指令和常量
RW是程序中的已初始化变量
ZI是程序中的未初始化的变量
由以上3点说明可以理解为:
RO就是readonly,
RW就是read/write,
ZI就是zero
ARM映像文件的组成
所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。
Image文件包含了RO和RW数据。
之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。
Q:为什么Image中必须包含RO和RW?
A:因为RO中的指令和常量以及RW中初始化过的变量是不能像ZI那样“无中生有”的。
ARM程序的执行过程
从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。
实际上,RO中的指令至少应该有这样的功能:
1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中
在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。


注意:如果一个变量被初始化为0,则该变量的处理方法与未初始化华变量一样放在ZI区域。
即:ARM C程序中,所有的未初始化变量都会被自动初始化为0。
总结:
1; C中的指令以及常量被编译后是RO类型数据。
2; C中的未被初始化或初始化为0的变量编译后是ZI类型数据。
3; C中的已被初始化成非0值的变量编译后市RW类型数据。

编译后的信息就在aa.map文件中。
ROM主要指:NAND Flash,Nor Flash
RAM主要指:PSRAM,SDRAM,SRAM,DDRAM

简单的说就是在烧写完的时候是:FLASH中:Code+RO Data+RW Data,运行的时候:RAM: RW Data + ZI Data,当然还要有堆栈的空间。

参考:http://hi.baidu.com/turelife_2012/item/88dab9df1159acf692a9745a
回复 支持 反对

使用道具 举报

发表于 2013-6-12 20:03:17 | 显示全部楼层
受益良多
回复 支持 反对

使用道具 举报

发表于 2013-7-2 10:22:40 | 显示全部楼层
非常酷!
回复 支持 反对

使用道具 举报

发表于 2015-1-10 09:19:38 | 显示全部楼层
呵呵,还是下面那个链接里讲的详细。有例子参考,直观好多。
回复 支持 反对

使用道具 举报

发表于 2019-9-5 16:41:33 | 显示全部楼层
缺这部分知识,学习了。。。。。。
回复 支持 反对

使用道具 举报

发表于 2019-10-15 10:19:35 | 显示全部楼层
学到了!学到了!!学到了!!!
回复 支持 反对

使用道具 举报

发表于 2020-6-1 22:34:14 | 显示全部楼层
char a[]="abcde"; 是在.data区吗?我感觉是在栈上呢
回复 支持 反对

使用道具 举报

发表于 2020-9-16 07:23:50 | 显示全部楼层
liu521 发表于 2020-6-1 22:34
char a[]="abcde"; 是在.data区吗?我感觉是在栈上呢

我也觉得是栈,char a[]之后是可以修改成员的数组的,所以是在栈上。
回复 支持 反对

使用道具 举报

发表于 2021-3-12 18:55:27 | 显示全部楼层
学了,,,,,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-24 21:43 , Processed in 0.042036 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表