目录
一、归纳出Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址,进行对比分析
1、堆&栈
简介:
堆和栈都在RAM中,一般被分配的区域也是相同的一块区域,只是堆从下往上存储,栈从上往下存储。此时应该注意堆和栈在不断增长的过程可能会互踩内存,就会出现意外error,所以在使用时应该注意用完堆栈及时释放或者划分的内存大一些。另外呢,栈是编译器自动分配和释放的,比如函数的参数、局部变量的值等。堆一般是程序员分配和释放的,分配方式类似于数据结构中的链表。
堆的动态内存分配:
堆允许程序在运行时动态分配和释放内存,而不需要在编译时预先知道内存大小或结构。这使得程序可以有效地管理不确定大小或生命周期的数据。
运行时内存管理:
编程语言中的栈也被用于运行时的内存管理。函数调用时,栈可以用于保存函数的返回地址、调用参数和局部变量等信息。这些数据在函数调用结束后会自动从栈中释放。
2、全局&局部变量
定义:
局部变量:
局部变量又被称为内部变量,是指在一个函数内部或复合语句内部定义的变量。局部变量的作用域是定义该变量的函数或定义该变量的复合语句。也就是说,局部变量只在定义它的函数或复合语句范围内有效,只能在定义它的函数或复合语句内才能使用它们。
全局变量:
全局变量又被称为外部变量,它属于一个源程序文件。全局变量既可以是某对象函数创建,也可以是在本程序任何地方创建。全局变量是可以被本程序所有对象或函数引用。
区别:
1、定义不同:局部变量指的是在函数内定义的变量,全局变量指的是在函数外定义的变量。
2、内存存储方式不同:全局变量存储在全局数据区中,局部变量存储在栈区。
3 、生命期不同:全局变量的生命期和主程序一样,随程序的销毁而销毁,局部变量在函数内部或循环内部,
随函数的退出或循环退出就不存在了。
4、使用方式不同:全局变量在声明后程序的各个部分都可以用到,但是局部变量只能在局部使用。
5、作用域不同:全局变量的作用域为整个程序,而局部变量的作用域为当前函数或循环等
存储区图解:
二、加深对ARM Cortex-M/stm32F10x的存储器地址映射的理解
1、ubuntu编译验证
代码
#include <stdio.h>
#include <stdlib.h>
// 全局常量
const int globalConstant = 10;
// 全局变量
int globalVariable = 20;
int main() {
// 局部变量
int localVar = 30;
// 静态变量
static int staticVar = 40;
// 堆上分配内存
int *heapVar = (int *)malloc(sizeof(int));
*heapVar = 50;
// 打印变量值
printf("Global Constant: %d\n", globalConstant);
printf("Global Variable: %d\n", globalVariable);
printf("Local Variable: %d\n", localVar);
printf("Static Variable: %d\n", staticVar);
printf("Heap Variable: %d\n", *heapVar);
// 释放堆内存
free(heapVar);
return 0;
}
编译实现
vim stm.c
gcc -E stm.c -o stm.i
gcc -S stm.i -o stm.s
gcc -C stm.s -o stm.o
gcc stm.c -o stm
./stm
结果展示:
2、stm32
代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "stm32f10x.h" // Device header
void UART_Init() {
// 使能USART1时钟
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
// 配置引脚
GPIOA->CRH |= GPIO_CRH_MODE9_0 | GPIO_CRH_CNF9_1; // TX引脚
GPIOA->CRH |= GPIO_CRH_CNF10_0; // RX引脚
// 配置USART1
USART1->BRR = 0x1D4C; // 波特率9600,根据系统时钟设置
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE; // 使能发送和接收
USART1->CR1 |= USART_CR1_UE; // 使能USART1
}
// 全局常量
const int globalConstant = 10;
// 全局变量
int globalVariable = 20;
void main(void)
{
// 局部变量
int localVar = 30;
// 静态变量
static int staticVar = 40;
// 栈分配内存
int stackVar = 60;
// 堆分配内存
int* heapVar = malloc(sizeof(int));
*heapVar = 50;
// 打开串口
// 这里假设串口初始化的代码已经被配置好
UART_Init();
// 初始化堆栈指针
SystemInit();
__disable_irq();
// 打印全局常量、全局变量、局部变量、静态变量、堆和栈的值
printf("Global constant: %d\r\n", globalConstant);
printf("Global variable: %d\r\n", globalVariable);
printf("Local variable: %d\r\n", localVar);
printf("Static variable: %d\r\n", staticVar);
printf("Heap variable: %d\r\n", *heapVar);
printf("Stack variable: %d\r\n", stackVar);
while (1)
{
// 主循环
}
}
3、存储器地址映射一般理解
stm32数据的存储位置
RAM(随机存取存储器)
存储的内容可通过指令随机读写访问。RAM中的存储的数据在掉电是会丢失,因而只能在开机运行时存储数据。其中RAM又可以分为两种,一种是Dynamic RAM(DRAM动态随机存储器),另一种是Static RAM(SRAM,静态随机存储器)。栈、堆、全局区(.bss段、.data段)都是存放在RAM中。
ROM(只读存储器)
只能从里面读出数据而不能任意写入数据。ROM与RAM相比,具有读写速度慢的缺点。但由于其具有掉电后数据可保持不变的优点,因此常用也存放一次性写入的程序和数据,比如主版的BIOS程序的芯片就是ROM存储器。代码区和常量区的内容是不允许被修改的,所以存放于ROM中。
内部Flash存储器
这是微控制器上的主要程序存储器,用于存储应用程序代码。通常,Flash存储器的地址从0x08000000开始,一直延伸到0x080FFFFF,其中一部分地址可能用于引导程序和存储器保护。
SRAM(静态随机访问存储器)
SRAM用于存储变量和临时数据,是RAM类型的存储器。在STM32微控制器中,SRAM通常映射到地址0x20000000开始的地址范围,一直延伸到0x200FFFFF,其中一部分用于堆栈、全局变量等。
外设寄存器
STM32微控制器包含了许多外设(如UART、SPI、I2C、GPIO等),它们的配置和控制寄存器通常映射到特定的地址范围,以便通过访问这些地址来配置和控制外设。
系统控制寄存器
这些寄存器用于配置和控制微控制器的系统特性,例如,时钟、复位、中断控制等。它们通常映射到特定的地址范围,以便进行系统级设置。
参考链接
1、局部变量与全局变量的区别
2、STM32 KEIL下的堆栈设置
3、基于ubuntu,树莓派和stm32的C程序的内存分配问题
4、【嵌入式18】Ubuntu、stm32下的程序内存分配问题(堆栈、局部全局变量等)
5、ARM Cortex-M架构基本概念
6、STM32之变量存储位置解析(根据地址分析)