编写一个C程序,重温全局常量、全局变量、局部变量、静态变量、堆、栈等概念,在Ubuntu(x86)系统和STM32(Keil)中分别进行编程、验证

一、归纳出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之变量存储位置解析(根据地址分析)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值