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

全局变量是否占用最终程序的存储空间,这个问题其实早在我们学习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运行时库提供的代码,是由链接器把他们嵌入到你的用户代码里的。

现在,对于变量的空间分配,你是不是更了解了一些呢?


=========================================================================================================================

5月11日修改:

后来在阿莫电子论坛(http://www.amobbs.com)上有人看了本片文章后提出了反对意见,告诉我说FLASH空间=Code + RO Data + RW Data。为了验证这一点,我做了一个小测试,发现果然如上所说。验证试验如下:


建立一个最简单的工程,如下图:

sshot-4.png 

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文件:
sshot-5.png 
别忘了设置程序入口点,这里设置_mian为程序入口点,防止编译产生警告。

bin文件格式转换设置:
sshot-6.png 

工程设置完毕后,编译、链接,最终结果如下图:
sshot-7.png 
可以看到Code代码段占用16字节,只读数据段RO Data为0字节,读写数据段RW Data为1024字节。这是我们找到生成的test.bin文件查看其大小刚好为1040字节=Code(16) + RO Data(0) + RW Data(1024),如下图:
sshot-8.png 

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

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


  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
全局变量在中断中的使用需要注意一些问题。首先,中断中使用的全局变量在其他函数内使用时,需要进入临界区(关闭中断)。这是因为中断可能会在任何时候发生,如果在中断处理过程中访问全局变量,而其他函数也在同时访问该全局变量,就会导致数据不一致的问题。所以,在其他函数内使用全局变量时,需要先进入临界区,确保中断不会干扰到全局变量的访问。\[1\] 其次,全局变量的大小只会影响到占用SRAM的大小,而不会影响目标代码的大小。目标代码的大小与程序中所申请的全局变量大小无关,只与代码段和只读数据段有关。目标代码会包含全局变量的分配空间的信息,比如起始地址、空间大小、是否要用0初始化等信息,但不会包含实际的存储空间全局变量的分配是在程序复位中断执行后,进入main函数之前进行的,由开发环境提供的C运行时库提供的代码来完成。\[2\] 在使用全局变量时,需要注意不同文件之间的变量声明和定义。如果在main.c文件中声明了一个全局变量,比如u8 biaozhi=0,然后在stm32f10x_it.c文件中再次声明了一个同名的全局变量,volatile u8 biaozhi,这样两个文件就可以共享同一个变量biaozhi。但是需要注意的是,这种共享全局变量的方式可能会导致数据不一致的问题,因为中断和主循环可能会同时访问该全局变量。所以,在使用共享全局变量时,需要谨慎处理数据同步的问题,确保数据的一致性。\[3\] #### 引用[.reference_title] - *1* [STM32中,关于中断函数调用全局变量的问题](https://blog.csdn.net/leo_liu006/article/details/79334905)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [STM32全局变量占用程序存储空间吗](https://blog.csdn.net/weixin_35896299/article/details/117096817)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [stm32中断函数改变全局变量值](https://blog.csdn.net/wds2435629591/article/details/56481854)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值