C 语言变量在单片机 Flash 与 SRAM 中的存储分布 本文基于Cortex‑M内核单片机STM32讲解51单片机原理类似适合嵌入式入门学习。编译链接后程序会被划分成不同段(section)变量所属段决定了它存放在Flash还是SRAM。一、存储器基础概念Flash闪存非易失性存储器断电后数据不会丢失。特性读取速度快擦写速度慢需要按页擦除程序运行期间Flash区域只读。主要用途存放程序代码、常量字符串、const只读常量。SRAM静态随机存储器易失性存储器断电数据全部丢失。特性读写速度极快支持随机读写。主要用途存放全局变量、局部变量、栈、堆。核心一句话Flash存“样板/代码”SRAM存“运行时可读写变量”二、存储器直观示意图Flash 存放代码与只读常量SRAM存放运行时可读写变量。Flash ┌────────────┬────────────┐ │ .text段 .rodata段 └────────────┴────────────┘ .text程序代码指令 .rodataconst常量、字符串字面量只读断电不丢失 SRAM ┌──────────┬──────────┬──────────┬──────────┬──────────┐ │ .data段 .bss段 .heap段 .stack段 └──────────┴──────────┴──────────┴──────────┴──────────┘ .data用来存放有初始值的全局变量或静态变量 .bss用来存放无初始值或初始值为0的全局变量或静态变量 .heap段用来存放“堆”malloc分配的内存 .stack段用来存放“栈”局部变量参数等不包括静态局部变量三、程序五大核心段段名存储位置存放内容初始化规则.text代码段Flash函数指令、程序代码烧录固化运行只读.rodata只读常量段Flashconst全局常量、字符串字面量烧录固化运行不可修改.data已初始化全局变量段Flash存放初始镜像上电拷贝到SRAM全局/静态变量定义时赋初值int a10;MCU启动代码把Flash里的初始值复制到SRAM.bss未初始化全局变量段SRAM全局/静态变量未初始化int b;或初始化为0int a0;上电启动时程序自动清零不占用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. 普通局部变量函数内无staticvoid test(void){ int loc_a 1; // 栈SRAM函数调用分配函数结束销毁 char str[]abc; // 数组字符串拷贝到栈内存可以修改 const int loc_c5; // 局部const一般放在栈部分编译器优化到rodata }⚠️ 单片机栈空间很小通常几KB禁止定义超大局部数组极易栈溢出导致死机。4. 字符串常量char *p hello;hello字符串字面量存放在.rodataFlash指针变量p本身是局部变量存放在栈SRAM。尝试执行p[0]H修改会触发硬件异常Flash区域只读对比char str[]hello;字符串初始样板存Flash程序运行时拷贝到栈SRAMstr数组内容可以修改。五、单片机上电启动流程理解.data拷贝关键上电复位执行启动汇编文件startup_stm32f10x.s将.data段的初始数据从Flash复制到SRAM将.bss段内存全部清零初始化堆栈指针SP调用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 imageSTM32CubeIDE编译输出.map文件查看section地址与占用CodeFlash占用textrodataRO-data只读常量RW-data.data段SRAM占用ZI-data.bss段SRAM占用八、总结单片机C程序经过编译链接会划分成多个存储段。.text代码段与.rodata只读常量段存储于Flash断电数据不丢失。已初始化全局/静态变量归属.data段初始镜像保存在Flash上电拷贝至SRAM未初始化全局、静态变量属于.bss段位于SRAM启动阶段自动清零。普通局部变量存放在SRAM栈空间函数调用动态分配。SRAM属于易失存储器断电数据丢失。 合理掌握变量存储位置可以有效优化单片机RAM资源规避栈溢出、内存访问异常等问题。