Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址,进行对比分析

一、基本概念

全局常量是在程序运行期间不可更改的常量,它们的值在程序的整个执行过程中保持不变。

全局变量是在程序的任何地方都可以访问的变量,在整个程序执行期间都会存在,并且可以在不同的函数之间共享数据。

局部变量是在一个特定的代码块或函数中定义的变量,它们的作用域只在其所在的代码块或函数中,当代码块或函数执行完毕后,局部变量会被销毁。

静态变量是在程序执行过程中一直存在的变量,它的生命周期从变量的声明到程序结束。静态变量在内存中的位置固定不变,而且只会被初始化一次。

是用于动态内存分配的一种数据结构,它是在程序运行时动态分配内存空间的一块区域。堆中的内存可以通过new关键字或者类似的分配函数进行手动管理,同时在合适的时机需要手动释放内存。

是一种数据结构,它用于存储函数调用的参数、局部变量等数据。栈是自动分配和释放内存的,每当函数被调用时,其局部变量和参数都会被压入栈中,当函数执行完毕后,这些数据会被自动释放。栈的大小一般是由系统预先设定的,不建议在栈中存储过大的数据。

二、ubuntu下的地址分配

1.编写代码

首先在Ubuntu系统上编写c语言代码,示例如下:

#include <stdio.h>
#include <stdlib.h>

int global_var;       // 全局变量
const int global_const = 10;   // 全局常量

int main() {
    int local_var;    // 局部变量
    static int static_var;    // 静态变量

    int *heap_var = (int *)malloc(sizeof(int));    // 动态分配堆内存

    printf("地址比较结果:\n");
    printf("全局变量地址:%p\n", &global_var);
    printf("全局常量地址:%p\n", &global_const);
    printf("局部变量地址:%p\n", &local_var);
    printf("静态变量地址:%p\n", &static_var);
    printf("堆变量地址:%p\n", heap_var);
    
    free(heap_var);    // 释放堆内存

    return 0;
}

 2.输出结果

由以上结果可以看出,在Ubuntu中,除.bss段,其余所有区的内存分配都是从上向下不断增长的。

三、stm32下的地址分配 

KEILL MDK调试环境下的内存分配具体说明

IROM1为默认分配的ROM区域,由0x8000000开始,大小为0x80000。

IRAM1为默认分配的RAM区域,由0x20000000开始,大小为0x10000。

类似的代码,但是需要初始化串口,按照参考文献2中的新建模板工程进行建立就好了。

#include "sys.h"
#include "usart.h"		
#include "delay.h"	 
#include <stdio.h>
#include <stdlib.h>
//定义全局变量
int init_global_a = 1;
int uninit_global_a;
static int inits_global_b = 2;
static int uninits_global_b;
void output(int a)
{
	printf("the result is:");
	printf("\n");
}

int main(void)
{				 
	u16 t; u16 len; u16 times=0;
	Stm32_Clock_Init(9);	//系统时钟设置
	delay_init(72);	  		//延时初始化
	uart_init(72,115200); 	//串口初始化为115200
	
	
	
  	while(1)
	{
		int a=2;
	static int inits_local_c=2, uninits_local_c;
    int init_local_d = 1;
    output(a);
    char *p;
    char str[20] = "wuwuwuwuwuwu";
    //定义常量字符串
    char *var1 = "123456";
    char *var2 = "abcdef";
    //动态分配
    int *p1=malloc(4);
    int *p2=malloc(4);
    //释放
    free(p1);
    free(p2);
    printf("栈区-变量地址\n");
    printf("                a:%p\n", &a);
    printf("                init_local_d:%p\n", &init_local_d);
    printf("                p:%p\n", &p);
    printf("              str:%p\n", str);
    printf("\n堆区-动态申请地址\n");
    printf("                   %p\n", p1);
    printf("                   %p\n", p2);
    printf("\n全局区-全局变量和静态变量\n");
    printf("\n.bss段\n");
    printf("全局外部无初值 uninit_global_a:%p\n", &uninit_global_a);
    printf("静态外部无初值 uninits_global_b:%p\n", &uninits_global_b);
    printf("静态内部无初值 uninits_local_c:%p\n", &uninits_local_c);
    printf("\n.data段\n");
    printf("全局外部有初值 init_global_a:%p\n", &init_global_a);
    printf("静态外部有初值 inits_global_b:%p\n", &inits_global_b);
    printf("静态内部有初值 inits_local_c:%p\n", &inits_local_c);
    printf("\n文字常量区\n");
    printf("文字常量地址     :%p\n",var1);
    printf("文字常量地址     :%p\n",var2);
    printf("\n代码区\n");
    printf("程序区地址       :%p\n",&main);
    printf("函数地址         :%p\n",&output);

		if(USART_RX_STA&0x8000)//串口发送部分
		{ 
			len=USART_RX_STA&0x3FFF;//得到此次接收到的数据长度
			
			for(t=0;t<len;t++)
			{
				USART1->DR=USART_RX_BUF[t];
				while((USART1->SR&0X40)==0);//等待发送结束
			}
			
			USART_RX_STA=0;
		}else
		{
			times++;
		
			delay_ms(100); 
		}
	}	 
	return 0;
} 

将代码导入keil中进行调试,发现报错。

此时需要进行调试设置,因为声明不能出现在可执行状态之后,C语言关于变量的定义只能放在函数的开头,放在执行语句的前面定义,这是C89的标准。后来的C99标准就已经改变了,无论定义在之前还是之后都是可以的。

所以我们打开魔术棒,再点c/c++,打钩上C99 mode 即可。

随后,在“Target”选项中勾选 “Use MicroLIB”

这样就可以调试成功了,我们将代码烧录到芯片中。

然后打开串口调试助手

可以发现,在STM32中,栈区的地址是自下而上增加的,与Linux系统恰好相反;堆区地址则是从上向下增长。

四、总结

  1. 堆(Heap):

    • 在Ubuntu中,堆是由malloc、calloc或realloc等动态内存分配函数分配的内存区域。堆是由操作系统动态分配的,大小可根据需要进行增加或减少。
    • 在STM32中,堆的实现通常需要通过重定向malloc和free函数,并在启动文件中指定堆的起始地址和大小。
  2. 栈(Stack):

    • 在Ubuntu中,栈用于存储函数的局部变量和函数调用的相关信息。栈的分配和释放是由编译器和操作系统完成的,通常具有固定的大小,存储顺序为后进先出。
    • 在STM32中,栈用于保存函数的局部变量、函数参数和返回地址等信息。栈的大小通常在编译时由链接器和启动文件定义,存储顺序也是后进先出。
  3. 全局变量(Global Variables):

    • 在Ubuntu和STM32中,全局变量是定义在函数外部或在文件作用域中的变量。全局变量在程序启动时就被分配到静态存储区,包括存储于数据段或BSS段,并且在整个程序生命周期内都是有效的。
  4. 局部变量(Local Variables):

    • 在Ubuntu中,局部变量是定义在函数内部的变量。它们通常存储在栈上,并在函数执行期间使用,并在函数返回时释放。
    • 在STM32中,局部变量也存储在栈上。由于STM32通常具有较小的内存资源,函数执行完成后栈上的局部变量会自动释放。

总体上,Ubuntu和STM32在内存管理方面有一些差异。Ubuntu操作系统拥有较为完善的内存管理系统,可以通过动态内存分配来灵活管理堆的大小。而在STM32嵌入式系统中,由于资源限制,内存管理方面需要更加谨慎,并通过静态定义和栈的使用来实现变量的分配和释放。

五、参考

C语言内存分配_c的内存分配-CSDN博客

【嵌入式09】STM32串口通信,发送Hello Windows示例_windiw电脑与嵌入式通信-CSDN博客

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值