ubuntu和stm32下的C程序的内存分配问题

题目要求

编写一个C程序,重温全局变量、局部变量、堆、栈等概念,在Ubuntu(x86)系统和STM32(Keil)中分别进行编程、验证(STM32 通过串口printf 信息到上位机串口助手) 。归纳出Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址,进行对比分析。

一、内存分配

在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。
总的分布如下所示:
在这里插入图片描述
一、栈区(stack)

临时创建的局部变量存放在栈区。

函数调用时,其入口参数存放在栈区。

函数返回时,其返回值存放在栈区。

const定义的局部变量存放在栈区。

2、堆区(heap)

堆区用于存放程序运行中被动态分布的内存段,可增可减。

可以有malloc等函数实现动态分布内存。

有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。

3、全局区(静态区)

全局区有.bss段和.data段组成,可读可写。

4、.bss段

未初始化的全局变量存放在.bss段。

初始化为0的全局变量和初始化为0的静态变量存放在.bss段。

.bss段不占用可执行文件空间,其内容有操作系统初始化。

5、.data段

已经初始化的全局变量存放在.data段。

静态变量存放在.data段。

.data段占用可执行文件空间,其内容有程序初始化。

const定义的全局变量存放在.rodata段。

6、常量区

字符串存放在常量区。

常量区的内容不可以被修改。

7、代码区

程序执行代码存放在代码区。

字符串常量也有可能存放在代码区。

二、ubuntu和stm32编程验证

ubuntu验证

首先创建一个文件夹

gedit test.c

在新建文件夹中添加以下代码保存

#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("hello");
	printf("%d",a);
	printf("\n");
}

int main( )
{   
	//定义局部变量
	int a=2;
	static int inits_local_c=2, uninits_local_c;
    int init_local_d = 1;
    output(a);
    char *p;
    char str[10] = "lmy";
    //定义常量字符串
    char *var1 = "1234567890";
    char *var2 = "qwertyuiop";
    //动态分配
    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);
    return 0;
}


请添加图片描述
编译运行代码

gcc test.c -o test

./test

请添加图片描述
可以发现,Ubuntu在栈区和堆区的地址值都是从上到下增长的。

stm32验证

改写以前的串口通信文件
将main.c改为

#include "usart.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("hello");
	printf("%d",a);
	printf("\n");
}

int main(void)
{	
	uart_init(115200);	
		while(1)
	{
		//定义局部变量
		int a=2;
		static int inits_local_c=2, uninits_local_c;
		int init_local_d = 1;
		char *p;
		char str[10] = "zls";
		//定义常量字符串
		char *var1 = "1234567890";
		char *var2 = "qwertyuiop";
		//动态分配
		int *p1=malloc(4);
		int *p2=malloc(4);
		output(a);
		//释放
		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);
		return 0;
  }
}


然后按部就班的编译、烧录到板子里,用串口助手可以查看
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值