搜索
bottom↓
回复: 39

STM32全局变量占用程序存储空间吗?

[复制链接]

出0入0汤圆

发表于 2013-5-10 02:15:50 | 显示全部楼层 |阅读模式
全局变量是否占用最终程序的存储空间,这个问题其实早在我们学习C语言的时候就已经告诉我们答案了。我隐约记得初学C语言的时候,书本上告诉我们:
全局自动变量——保存在读写数据段
全局静态变量——保存在读写数据段
全局常量——保存在只读数据段
局部自动变量——保存在栈空间里的
而我们在做单片机程序的时候,由于都是用的C编程,所以数据的存储也是一样的。上面的读写数据段在单片机里就是RW-data段,上面的只读数据段在单片机里就是RO-data,还有一个零初始化数据段ZI-data段(由此可见,RW-data加上ZI-data就是总共要分配的RAM空间大小),最后一个Code段就不用介绍了,大家都明白。
那么究竟一个STM32程序编译链接完成后的BIN文件大小到底跟所申请的全局变量有没有关系呢?答案是无关!最终生成的BIN文件大小只与程序的代码段(Code段)和只读数据段(RO-data)有关,即BIN文件大小=Code段+RO-data段。
为了验证这一点,我特地拿正点原子战舰开发板的案例《实验48 串口IAP实验》来给大家演示,证明目标代码的大小与程序中所申请的全局变量大小无关。选择正点原子的这个案例有两个原因:1.本人目前正在学习STM32 IAP编程;2.该例程中分配了一个全局变量u8 USART_RX_BUF[USART_REC_LEN],USART_REC_LEN的长度为55K,几乎占用了80%的SRAM空间,对本文的论点起着典范作用。
首先我们不对工程进行修改,如下图:

编译链接后,生成的目标代码结果如下:

可以看到,Program Size: Code=19208 RO-data=3036 RW-data=64 ZI-data=62400  
得出ROM=21.7K RAM=61K

我们再将USART_REC_LEN宏的长度修改为55,空间大大缩小,如下图:

编译链接后,目标代码大小如下:

可以看到Program Size: Code=19208 RO-data=3036 RW-data=64 ZI-data=6136  
得到ROM=21.7K RAM=6K

而两次编译后,我们到工程目录下找到IAP.BIN文件,查看该文件的大小,都是21.7K,如下图:


由此可见,目标代码的大小与程序中所申请的全局变量大小无关,而只与代码段(Code段)和只读数据段(RO-data段)有关,而全局变量的大小只会影响到占用SRAM的大小。那么既然最终的目标代码大小跟全局变量的大小无关,是不是目标代码就一点也不包含全局变量了呢?呵呵,如果不包含全局变量,那程序运行的时候就不知道全局变量在哪里啦!当然会包含全局变量啦,只是不是包含它们的存储空间,而是包含他们分配空间的信息,比如该全局变量的起始地址、空间大小、是否要用0初始化等信息,这样就只会占用目标代码非常少的空间。那全局变量又是在什么时候分配的呢?全局变量的分配是在程序复位中断执行后,进入main函数之前分配的。那么全局变量又是由谁来分配的呢?全局变量的分配工作在你的用户程序中是看不到的,它们是有开发环境提供的C运行时库提供的代码,是由链接器把他们嵌入到你的用户代码里的。
现在,对于变量的空间分配,你是不是更了解了一些呢?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2013-5-10 02:21:42 | 显示全部楼层
深夜来顶楼主~

出0入0汤圆

发表于 2013-5-10 02:59:19 | 显示全部楼层
讲得很好

出0入0汤圆

发表于 2013-5-10 08:08:49 | 显示全部楼层
我觉得这就是理所当然的,除非你在声明全局变量时就向里面填充了内容,不然不会增加ROM占用空间。
比如char str[10]="Hello!",虽然这个字符串是在RAM的,但是ROM也包含了这个字符串的内容和复制内容到RAM的程序,在初始化的时候就会执行程序把ROM的内容复制到RAM中分配的空间里。

出0入0汤圆

发表于 2013-5-10 08:13:13 | 显示全部楼层
顶一个!楼主半夜还发帖啊!

出0入0汤圆

发表于 2013-5-10 08:26:51 | 显示全部楼层
XA144F 发表于 2013-5-10 08:08
我觉得这就是理所当然的,除非你在声明全局变量时就向里面填充了内容,不然不会增加ROM占用空间。
比如char ...

就是这样。

出0入0汤圆

 楼主| 发表于 2013-5-10 13:10:06 | 显示全部楼层
XA144F 发表于 2013-5-10 08:08
我觉得这就是理所当然的,除非你在声明全局变量时就向里面填充了内容,不然不会增加ROM占用空间。
比如char ...

你说的很对,因为“Hello!”是常量,常量就是保存在只读数据段的,所以会占用ROM的大小,而至于将这些常量复制到RAM的执行代码只会占用很小一部分ROM空间的,所以最终目标代码的大小还是由代码段和只读数据段决定的。
你对于C语言的内存管理很熟悉呀!

出0入0汤圆

发表于 2013-5-10 13:36:25 | 显示全部楼层
本帖最后由 qllaoda1 于 2013-5-10 13:38 编辑

常识性问题


Program Size: Code=86496 RO-data=9064 RW-data=1452 ZI-data=16116

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

全局变量和静态变量,如果定义的时候初始化,就统计在RW Data,如果没有,就统计在ZI-Data

出0入0汤圆

发表于 2013-5-10 13:45:40 | 显示全部楼层
赞!~                          

出0入0汤圆

发表于 2013-5-10 13:56:49 | 显示全部楼层
进入main函数之前的操作是初始化变量,而不是分配,分配是由编译器和链接器完成的。

出0入0汤圆

 楼主| 发表于 2013-5-10 14:08:03 | 显示全部楼层
qllaoda1 发表于 2013-5-10 13:36
常识性问题

你的这句话“FLASH中的被占用的空间为:Code + RO Data + RW Data”,确实是要加上RW Data的空间大小吗?我觉得FLASH应该只是包含了RW Data的一些基本信息,比如起始地址、空间大小、初值地址等信息,而不是整个RW Data的大小吧?
初来乍到,请多多指教!

出0入0汤圆

发表于 2013-5-10 14:40:11 | 显示全部楼层
char ch[]="jack slow fuck";
就是典型的RW,这个字符串在flash里面有,开机后还要复制到ram里面,所以RW既占用flash也占用ram

出0入17汤圆

发表于 2013-5-10 14:56:35 | 显示全部楼层
hexiaolong2009 发表于 2013-5-10 14:08
你的这句话“FLASH中的被占用的空间为:Code + RO Data + RW Data”,确实是要加上RW Data的空间大小吗? ...

前面认同了char str[10]="Hello!",后面就开始反悔。他们讲的是同一件事

出0入0汤圆

发表于 2013-5-10 15:02:53 | 显示全部楼层
你以为我会被你误导么。

出0入0汤圆

发表于 2013-5-10 21:27:34 | 显示全部楼层
char ch[]="jack slow fuck";
这是两句.....不是一句....

出0入0汤圆

 楼主| 发表于 2013-5-11 22:37:45 | 显示全部楼层
嗯,楼上说的都对,我验证过了,最终生成的目标代码大小=Code+RO Data+RW Data。实验如下:
建立一个最简单的工程,如下图:


main.c源码如下:
unsigned char var[1024]={          
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
"ffffffffffffffff"
};      



int _main(void)
{
unsigned char i;

        while(1)
        {
                i = var[0];
                i++;
        }
}

工程中只有1个main.c文件,该文件也很简单,就1个全局变量unsigned char var[1024],和一个_main函数。这里用_main而不用main是因为main函数会让链接器自动添加C库函数启动代码,而C库函数启动代码又会对全局数据进行压缩处理,这样就会是我们最终得到的BIN文件缩水,所以我这里使用_main函数就不会自动链接C库函数启动代码了。对工程的设置如下:
分散加载文件使用自己编写的sct文件:

别忘了设置程序入口点,这里设置_mian为程序入口点,防止编译产生警告。

bin文件格式转换设置:


工程设置完毕后,编译、链接,最终结果如下图:

可以看到Code代码段占用16字节,只读数据段RO Data为0字节,读写数据段RW Data为1024字节。这是我们找到生成的test.bin文件查看其大小刚好为1040字节=Code(16) + RO Data(0) + RW Data(1024),如下图:


本来我以为数组中的字符串“ffffffffffffffff”.....都是常量,照理说应该将它们划分到RO Data段的,可是MDK刚好跟我想的相反,把他们的大小规划到RW Data段了,而RO Data段则不包括它们的大小。
如果将原来的全局变量改成const类型,那么很容易想到,RO Data就变为1024字节,而RW Data就变为0字节,如下图:


所以最终得出结论,最终占用FLASH空间大小的因素是由Code、RO Data、RW Data这三个空间决定的,一般情况下,是小于等于Code+RO Data+RW Data,因为C库函数启动代码会对数据进行压缩处理。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-5-11 22:42:11 | 显示全部楼层
工程源码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入17汤圆

发表于 2013-5-11 22:52:12 | 显示全部楼层
占不占空间要看变量有没有被初始化;
初始化了没用过,可能被优化了也不会占空间

出0入0汤圆

 楼主| 发表于 2013-5-11 23:35:02 | 显示全部楼层
hhxb 发表于 2013-5-11 22:52
占不占空间要看变量有没有被初始化;
初始化了没用过,可能被优化了也不会占空间 ...

嗯,编译器的优化等级也会影响到最终的程序大小的。

出0入0汤圆

发表于 2013-5-11 23:41:01 来自手机 | 显示全部楼层
Mark…
来自:amoBBS 阿莫电子论坛 Windows Phone 7 客户端
头像被屏蔽

出0入0汤圆

发表于 2013-5-12 12:37:01 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2013-11-27 19:09:22 | 显示全部楼层
hexiaolong2009 发表于 2013-5-11 22:37
嗯,楼上说的都对,我验证过了,最终生成的目标代码大小=Code+RO Data+RW Data。实验如下:
建立一个最简单 ...

那此时需要的ram为多少呢?

出0入0汤圆

发表于 2013-11-27 21:29:30 | 显示全部楼层
好吧,lz值得鼓励,大概lz上份工是幼稚园的阿姨工作。。。。

出0入0汤圆

发表于 2013-11-27 21:33:07 来自手机 | 显示全部楼层
呵呵,学习了

出0入0汤圆

发表于 2013-11-27 22:03:52 | 显示全部楼层

唉。。。你对ZI理解是错的。。。ZI != Zero Initialize
看来搞清缩写的全称到底是什么 很重要。。。

出0入0汤圆

发表于 2013-11-28 11:10:32 | 显示全部楼层
caixiuwen 发表于 2013-11-27 22:03
唉。。。你对ZI理解是错的。。。ZI != Zero Initialize
看来搞清缩写的全称到底是什么 很重要。。。 ...

请指教。

出0入0汤圆

发表于 2013-11-28 12:24:31 | 显示全部楼层

ZI是Zero Initialized,就少了个d,意思可不一样。。。
没有显式初始化的全局变量、静态变量都被初始化成0了。
ZI-data说的就是初始化为零的数据,而不是说没有初始化。
真正没有初始化的叫uninitialized。。。

出0入0汤圆

发表于 2013-11-28 16:34:00 | 显示全部楼层
caixiuwen 发表于 2013-11-28 12:24
ZI是Zero Initialized,就少了个d,意思可不一样。。。
没有显式初始化的全局变量、静态变量都被初始化成 ...

ZI 对应的就是在C代码里只定义,没初始化的变量吧。

出0入0汤圆

发表于 2013-11-28 16:47:37 | 显示全部楼层
qllaoda1 发表于 2013-11-28 16:34
ZI 对应的就是在C代码里只定义,没初始化的变量吧。

现象是这么个现象,只是解释得不对

出0入0汤圆

发表于 2013-11-29 17:55:33 | 显示全部楼层
caixiuwen 发表于 2013-11-28 16:47
现象是这么个现象,只是解释得不对

学习了

请问Code,RO-data, RW-data的含义是不是在keil的文档里有说明啊?

出0入0汤圆

发表于 2013-11-29 21:56:04 | 显示全部楼层
mahengyu 发表于 2013-11-29 17:55
学习了

请问Code,RO-data, RW-data的含义是不是在keil的文档里有说明啊?

有的。打开帮助搜索一下。也可谷歌一下、维基一下

出0入0汤圆

发表于 2013-11-29 22:28:27 | 显示全部楼层
学习了      

出0入0汤圆

发表于 2014-3-6 22:27:41 | 显示全部楼层
mark,学习

出0入0汤圆

发表于 2014-6-18 16:01:35 | 显示全部楼层
谢谢,说得很好

出0入0汤圆

发表于 2014-6-18 22:37:58 | 显示全部楼层
长知识了。呵呵。

出0入0汤圆

发表于 2015-1-11 18:47:13 | 显示全部楼层
本帖最后由 lyricpoem0726 于 2015-1-11 18:50 编辑


楼主这个作何解释??
第二幅图在第一幅图的基础上加了 const unsigned char var[1024] = .............

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2015-1-11 21:33:04 | 显示全部楼层
lyricpoem0726 发表于 2015-1-11 18:47
楼主这个作何解释??
第二幅图在第一幅图的基础上加了 const unsigned char var[1024] = ............. ...

这个需要你把整个代码贴上来才能分析,光这么一小块也看不清你到底是怎么写的,而且你第一张图为什么RW Data有1036这么大?不知道你的全局变量都定义了什么。。。。

出0入0汤圆

发表于 2015-1-11 22:05:32 | 显示全部楼层
本帖最后由 lyricpoem0726 于 2015-1-11 22:08 编辑
hexiaolong2009 发表于 2015-1-11 21:33
这个需要你把整个代码贴上来才能分析,光这么一小块也看不清你到底是怎么写的,而且你第一张图为什么RW D ...


我是在你贴的工程上改的,
图1是增加了几个变量,如下:

原来的那个大数组前面的const 去掉了;
unsigned int test;
unsigned int test1 = 100;

在函数_main()
{
        static unsigned int j = 10;
}

rw_data = 1024 + 3 *4 = 1036;

图2只是改变了一个地方,把大数组前面加上了const, 其他未动编译结果就是图2,
很是困惑

出0入0汤圆

 楼主| 发表于 2015-1-11 22:30:44 | 显示全部楼层
估计是被优化掉了吧!因为你定义的那几个变量都没有被使用到,看看编译器优化等级什么的是不是有改动。

出0入0汤圆

发表于 2015-1-11 22:53:33 | 显示全部楼层
hexiaolong2009 发表于 2015-1-11 22:30
估计是被优化掉了吧!因为你定义的那几个变量都没有被使用到,看看编译器优化等级什么的是不是有改动。 ...

工程没有做任何的修改,优化等级我看了一下,为0 没优化啊

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 21:37

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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