在Ubuntu系统和STM32(Keil)中分别进行编程显示分配地址并进行比较

一、C程序中的一些变量及内存分配

1、全局变量
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。
例如:

int a, b;  //全局变量
void func1(){
    //TODO:
}
float x,y;  //全局变量
int func2(){
    //TODO:
}
int main(){
    //TODO:
    return 0;
}

a、b、x、y 都是在函数外部定义的全局变量。C语言代码是从前往后依次执行的,由于 x、y 定义在函数 func1() 之后,所以在 func1() 内无效;而 a、b 定义在源程序的开头,所以在 func1()、func2() 和 main() 内都有效。
2、局部变量
定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。例如:

int f1(int a){
    int b,c;  //a,b,c仅在函数f1()内有效
    return a+b+c;
}
int main(){
    int m,n;  //m,n仅在函数main()内有效
    return 0;
}

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

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

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

文字常量区:
存放常量字符串。当程序结束后,常量字符串由系统释放 。

程序代码区:
存放函数体的二进制代码。
存储区可以用如下图片表示:
请添加图片描述
4、内存段
内存段可以分为:bss 段、data段、text段、堆(heap)和栈(stack)。

bss 段:

bss 段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域;

bss 是英文Block Started by Symbol的简称;

bss 段属于静态内存分配。

data 段:

数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域;

数据段属于静态内存分配。

text 段:

代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域;

这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序);

在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减;

当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);

当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

栈(stack):

栈又称堆栈,是用户存放程序临时创建的局部变量;也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量);除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中;由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场;

从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
5、内存管理
STM32 的存储器结构中 Flash,SRAM 寄存器和输入输出端口被组织在同一个 4GB 的线性地址空间内。

可访问的存储器空间被分成8个主要块,每个块为512MB。

FLASH存储下载的程序,SRAM是存储运行程序中的数据。

所以,只要不外扩存储器,写完的程序中的所有东西也就会出现在这两个存储器中。

一、在Ubuntu和Keil中显示变量地址分配

1、Ubuntu中运行

通过一段程序,在程序中定义全局变量和局部变量,并通过程序输出这些变量所保存的地址信息。

#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] = "swj";//栈
    //定义常量字符串
    char *var1 = "1234567890";
    char *var2 = "abcdefghij";
    //动态分配——堆区
    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;
}

运行结果:
请添加图片描述
观察可知,Ubuntu在栈区和堆区的地址值都是逐步在增长的。

2、Keil中运行

代码如下:

#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"

#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){//主程序
	u8 a=7,b=8;
	//初始化程序
	RCC_Configuration(); //时钟设置

	USART1_Init(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[10] = "swj";
    //定义常量字符串
    char *var1 = "1234567890";
    char *var2 = "abcdefghij";
    //动态分配
    int *p1=malloc(4);
    int *p2=malloc(4);
    //释放
    free(p1);
    free(p2);
    printf("栈区-变量地址\n\r");
    printf("                a:%p\n\r", &a);
    printf("                init_local_d:%p\n\r", &init_local_d);
    printf("                p:%p\n\r", &p);
    printf("              str:%p\n\r", str);
    printf("\n堆区-动态申请地址\n\r");
    printf("                   %p\n\r", p1);
    printf("                   %p\n\r", p2);
    printf("\n全局区-全局变量和静态变量\n\r");
    printf("\n.bss段\n");
    printf("全局外部无初值 uninit_global_a:%p\n\r", &uninit_global_a);
    printf("静态外部无初值 uninits_global_b:%p\n\r", &uninits_global_b);
    printf("静态内部无初值 uninits_local_c:%p\n\r", &uninits_local_c);
    printf("\n.data段\n\r");
    printf("全局外部有初值 init_global_a:%p\n\r", &init_global_a);
    printf("静态外部有初值 inits_global_b:%p\n\r", &inits_global_b);
    printf("静态内部有初值 inits_local_c:%p\n\r", &inits_local_c);
    printf("\n文字常量区\n\r");
    printf("文字常量地址     :%p\n\r",var1);
    printf("文字常量地址     :%p\n\r",var2);
    printf("\n代码区\n\r");
    printf("程序区地址       :%p\n\r",&main);
    printf("函数地址         :%p\n\r",&output);
        delay_ms(1000); //延时
	
	}
}

运行结果:
请添加图片描述观察可知,STM32的栈区地址逐渐减小,但是其堆区的地址是逐渐增大的。

总结

堆和栈空间分配

栈:向低地址扩展

堆:向高地址扩展

显然如果依次定义变量,先定义的栈变量的内存地址比后定义的栈变量的内存地址要大。先定义的堆变量的内存地址比后定义的堆变量的内存地址要小
堆和栈变量
栈:临时变量,退出该作用域就会自动释放。
堆:malloc变量,通过free函数释放。
堆和栈的区别:
stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。
stack的空间有限,heap是很大的自由存储区。
程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值