Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的地址分配

一、全局变量 & 局部变量

全局变量 在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件。

局部变量 定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数的内部就是无效的,再使用就会报错。

二者之间的区别

全局变量 局部变量 定义位置 在方法外部,直接写在类中 在方法内部 作用范围 整个类中都可以使用 只能在方法中使用 默认值 如果没有赋值,则有默认值,规则同数组 没有默认值,要使用必须手动赋值 内存位置 位于堆内存 位于栈内存

二、堆 & 栈

1、STM32中的堆栈

单片机是一种集成电路芯片,集成CPU、RAM、ROM、多种I/O口和中断系统、定时器/计数器等功能。CPU中包括了各种总线电路,计算电路,逻辑电路,还有各种寄存器。

stm32 有通用寄存器 R0‐ R15 以及一些特殊功能寄存器,其中包括了堆栈指针寄存器。 当stm32正常运行程序的时候,来了一个中断,CPU就需要将寄存器中的值压栈到RAM里,然后将数据所在的地址存放在堆栈寄存器中。 等中断处理完成退出时,再将数据出栈到之前的寄存器中,这个在C语言里是自动完成的。

2、程序的内存分配 一般程序占用的内存分为以下几个部分:

1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。它与数据结构中的堆是两回事,分配方式类似于链表。

3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束后有系统释放

4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放

5、程序代码区—存放函数体的二进制代码。

代码:

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

在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量去、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。

通过下面的思维导图对这部分内容进行详细的介绍

### STM32在Keil中变量初始化方法 在嵌入式开发环境中,尤其是针对STM32微控制器使用Keil进行编程时,正确初始化变量是一个重要的环节。以下是关于如何在Keil中为STM32正确初始化变量的具体说明。 #### 变量分类及其存储位置 在C语言中,变量可以根据其生命周期和作用域分为全局变量、静态变量局部变量以及动态分配变量。这些变量在不同的存储区域被初始化: - **全局变量**:定义在函数外部,具有整个程序运行期间的有效期。它们通常位于数据段(Data Segment),如果未显式赋初值,则放置于BSS段[^1]。 - **局部变量**:定义在函数内部,默认情况下存放在区。当函数调用结束时,局部变量会被销毁[^4]。 - **静态变量**:无论是全局还是局部声明为`static`的关键字修饰符都会使该变量在整个程序执行过程中保持存在状态。对于未初始化的静态局部变量也会自动置零并放入BSS段;而对于已初始化的情况则置于数据段[^1]。 - **变量**:通过标准库函数如malloc() 或 calloc() 动态申请内存空间得到的对象属于此类别。这类对象直到程序员释放之前一直有效[^4]。 #### 初始化示例代码 下面展示了一个简单例子来演示不同类型变量是如何初始化的: ```c #include "stm32f10x.h" // 定义一个全局变量, 并赋予初始值. int globalVar = 10; void SystemInit(void); int main(){ static int staticLocalVar; // 静态局部变量 { int localVar; // 自动类型的局部变量 // 使用 malloc 函数创建指向整数型指针 pHeap 的新对象 (假设成功). int* pHeap = NULL; if ((pHeap = (int*)malloc(sizeof(int))) != NULL){ *pHeap = 20; } printf("Global Variable Value:%d\n",globalVar); printf("Static Local Variable Address:%p\n",&staticLocalVar); printf("Automatic Type Local Variable Address:%p\n",&localVar); printf("Pointer To Heap Memory Content:%d\n",(*pHeap)); free(pHeap); // 记得释放不再使用的资源! } while(1){} // 主循环等待中断或其他事件触发处理逻辑... } ``` 此代码片段展示了四种常见类型变量(`globalVar`, `staticLocalVar`, `localVar`, 和由`malloc()`产生的匿名实体) 的初始化方式,并打印出了各自的信息以便观察实际效果[^3]。 #### Ubuntu vs STM32 地址分布差异比较 由于目标平台架构的不同(Ubuntu通常是X86体系结构而STM32基于ARM Cortex-M核心),即使采用相同源码编译链接后的最终可执行映像里各分区布局也可能有所区别。具体表现在以下几个方面: - 数据段起始偏移可能发生变化; - 增长方向相反——Linux环境下一般是从低地址向高地址扩展,而在裸机环境下的某些实现可能会反向操作; - 大小限制更加严格,需谨慎规划以防止溢出等问题发生[^4]。 综上所述,在Keil IDE下完成对STM32项目的配置之后,按照上述规则合理安排各类别的变量即可满足大多数应用场景需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值