news 2026/11/5 11:50:25

C 语言变量在单片机 Flash 与 SRAM 中的存储分布

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C 语言变量在单片机 Flash 与 SRAM 中的存储分布

本文基于Cortex‑M内核单片机(STM32)讲解,51单片机原理类似,适合嵌入式入门学习。编译链接后,程序会被划分成不同段(section),变量所属段决定了它存放在Flash还是SRAM。

一、存储器基础概念

Flash(闪存)

  • 非易失性存储器:断电后数据不会丢失。
  • 特性:读取速度快,擦写速度慢,需要按页擦除,程序运行期间Flash区域只读。
  • 主要用途:存放程序代码、常量字符串、const只读常量。

SRAM(静态随机存储器)

  • 易失性存储器:断电数据全部丢失。
  • 特性:读写速度极快,支持随机读写。
  • 主要用途:存放全局变量、局部变量、栈、堆。

核心一句话:Flash存“样板/代码”,SRAM存“运行时可读写变量”

二、存储器直观示意图

Flash 存放代码与只读常量,SRAM存放运行时可读写变量。

Flash ┌────────────┬────────────┐ │ .text段 .rodata段 └────────────┴────────────┘ .text:程序代码指令 .rodata:const常量、字符串字面量(只读,断电不丢失) SRAM ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │ .data段 .bss段 .heap段 .stack段 └──────────┴──────────┴──────────┴──────────┴──────────┘ .data用来存放有初始值的全局变量或静态变量 .bss用来存放无初始值或初始值为0的全局变量或静态变量 .heap段用来存放“堆”,malloc分配的内存 .stack段用来存放“栈”,局部变量,参数等(不包括静态局部变量)

三、程序五大核心段

段名存储位置存放内容初始化规则
.text代码段Flash函数指令、程序代码烧录固化,运行只读
.rodata只读常量段Flashconst全局常量、字符串字面量烧录固化,运行不可修改
.data已初始化全局变量段Flash存放初始镜像,上电拷贝到SRAM全局/静态变量,定义时赋初值(int a=10;)MCU启动代码把Flash里的初始值复制到SRAM
.bss未初始化全局变量段SRAM全局/静态变量,未初始化(int b;)或初始化为0(int a=0;)上电启动时,程序自动清零,不占用Flash空间
栈 StackSRAM局部变量、函数形参、返回地址、中断现场函数调用时动态分配,函数退出自动回收,地址由高向低增长
堆 HeapSRAMmalloc/free动态申请内存手动申请释放,地址由低向高增长,嵌入式项目很少使用

四、C语言各类变量详细存储位置

1. 全局变量(函数外部定义)

int g_a = 100; // .data段:初始值100存Flash,上电拷贝到SRAM int g_b; // .bss段:位于SRAM,上电自动置0,不占用Flash const int g_c = 200; // .rodata段,Flash,只读不可修改
  • 生命周期:整个程序运行全程有效。
  • static修饰全局变量:仅限制作用域为本文件,存储段不变。

2. 静态局部变量 static(函数内部)

void test(void){ static int s_a = 10; // .data段,初始值在Flash,变量本体在SRAM;仅初始化1次 static int s_b; // .bss段,SRAM,上电清零 }

⚠️ static局部变量不在栈中,存储规则和全局变量一致,作用域仅限当前函数。

3. 普通局部变量(函数内,无static)

void test(void){ int loc_a = 1; // 栈(SRAM),函数调用分配,函数结束销毁 char str[]="abc"; // 数组:字符串拷贝到栈内存,可以修改 const int loc_c=5; // 局部const:一般放在栈,部分编译器优化到rodata }

⚠️ 单片机栈空间很小(通常几KB),禁止定义超大局部数组,极易栈溢出导致死机。

4. 字符串常量

char *p = "hello";

"hello"字符串字面量存放在.rodata(Flash);指针变量p本身是局部变量,存放在栈(SRAM)。

尝试执行p[0]='H'修改会触发硬件异常,Flash区域只读!

对比:

char str[]="hello";

字符串初始样板存Flash,程序运行时拷贝到栈SRAM,str数组内容可以修改。

五、单片机上电启动流程(理解.data拷贝关键)

  1. 上电复位;
  2. 执行启动汇编文件startup_stm32f10x.s:
    • 将.data段的初始数据从Flash复制到SRAM;
    • 将.bss段内存全部清零;
  3. 初始化堆栈指针SP;
  4. 调用main(),正式运行C程序。

为什么.data要拷贝:Flash运行时只读,变量运行过程需要读写,因此初始样板保存在Flash,变量实体放到SRAM。

六、强制变量存放Flash(节省SRAM)

全局const常量默认存Flash,不占用SRAM。也可以通过GCC属性手动指定段:

// 存放在Flash,不占用SRAM,适合大查找表 const uint8_t table[] = {1,2,3,4,5};

七、查看存储分布(验证方法)

编译后生成.map内存映射文件,可以直观查看各段占用Flash、SRAM大小:

  • Keil MDK:开启map文件,查看Memory Map of the image
  • STM32CubeIDE:编译输出.map文件,查看section地址与占用
    • Code:Flash占用(text+rodata)
    • RO-data:只读常量
    • RW-data:.data段,SRAM占用
    • ZI-data:.bss段,SRAM占用

八、总结

单片机C程序经过编译链接,会划分成多个存储段。.text代码段与.rodata只读常量段存储于Flash,断电数据不丢失。已初始化全局/静态变量归属.data段,初始镜像保存在Flash,上电拷贝至SRAM;未初始化全局、静态变量属于.bss段,位于SRAM,启动阶段自动清零。普通局部变量存放在SRAM栈空间,函数调用动态分配。SRAM属于易失存储器,断电数据丢失。 合理掌握变量存储位置,可以有效优化单片机RAM资源,规避栈溢出、内存访问异常等问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/5 11:50:24

手机变成电脑的软件推荐 手机变电脑的软件怎么选

手机变成电脑的软件推荐哪个?出门在外只有手机,却要处理电脑上的文件、运行办公软件,或者远程帮家人调试主机,这种时候选对手机变成电脑的软件就格外重要。手机变成电脑的软件核心需求是操作跟手、画面清晰。综合对比多款工具后&a…

作者头像 李华
网站建设 2026/10/23 9:34:56

Claude Code实战:AI辅助从零搭建宠物生命周期管理App

最近我用 Claude Code 从零搭完了一个宠物生命周期管理 App,整个过程从需求梳理、工程初始化、功能开发到模块联调,基本都是在 AI 辅助下完成的。这篇文章就顺着这个项目讲讲全流程是怎么跑的,哪些地方顺畅,哪些地方踩了坑&#x…

作者头像 李华
网站建设 2026/10/23 23:59:17

超时计数器差一拍:启动、完成与到期的周期边界

超时计数器差一拍:启动、完成与到期的周期边界 “启动后等待 4 个时钟,没有完成就报超时”,看起来只需要一个计数器。但同样从 0 开始计数,有的实现第 4 个边沿超时,有的第 5 个边沿才超时;如果完成信号恰…

作者头像 李华
网站建设 2026/10/20 23:11:26

一次讲清五种常见BOM:工程、制造、计划、成本、服务

很多企业不是没有BOM,而是研发、生产、计划、财务、售后各有一套,真正出问题时,却没有一套能让所有部门都说得清。 研发按图纸定义了产品结构,生产拿到清单却发现缺少辅料和包装材料;计划根据BOM计算需求,结…

作者头像 李华
网站建设 2026/10/22 21:24:20

金属仓储环境无线通信技术对比——明治AKU Air星闪方案与WiFi、蓝牙、ZigBee参数差异

【对比对象】本文对比仓储场景中常见的WiFi、蓝牙、ZigBee、LoRa与星闪NearLink五类短距/长距无线技术,并以明治AKU Air无线组网方案作为星闪技术在仓储监测中的工程实现进行参数对照。所有数值均来源于各技术公开指标与明治官方规格书。 一、五类技术核心参数对照 …

作者头像 李华
网站建设 2026/10/23 9:28:59

LRU 缓存原理与 C++ 实践示例

文章目录LRU 缓存原理与 C 实践示例什么是 LRULRU 需要满足的操作数据结构选型C 常见使用场景完整可运行示例实际项目中的注意点开源工业级实现参考小结LRU 缓存原理与 C 实践示例 什么是 LRU LRU(Least Recently Used),最近最少使用&#…

作者头像 李华