目录
一、堆、栈、全局、局部等变量的概念
1.全局变量
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件。
2.局部变量
定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数的内部就是无效的,再使用就会报错。
全局变量 | 局部变量 | |
---|---|---|
定义位置 | 在方法外部,直接写在类中 | 在方法内部 |
作用范围 | 整个类中都可以使用 | 只能在方法中使用 |
默认值 | 如果没有赋值,则有默认值,规则同数组 | 没有默认值,要使用必须手动赋值 |
内存位置 | 位于堆内存 | 位于栈内存 |
3.堆、栈
- 栈区(stack):指那些由编译器在需要的时候分配,不需要时自动清除的变量所在的储存区,如函数执行时,函数的形参以及函数内的局部变量分配在栈区,函数运行结束后,形参和局部变量去栈(自动释放)。栈内存分配运算内置与处理器的指令集中,效率高但是分配的内存空间有限。
- 堆区(heap):指哪些由程序员手动分配释放的储存区,如果程序员不释放这块内存,内存将一直被占用,直到程序运行结束由系统自动收回,c语言中使用malloc,free申请和释放空间。
- 静态存储区(static):全局变量和静态变量的储存是放在一块的,其中初始化的全局变量和静态变量在一个区域,这块空间当程序运行结束后由系统释放。
- 常量存储区(const):常量字符串就是储存在这里的,如“ABC”字符串就储存在常量区,储存在常量区的只读不可写。const修饰的全局变量也储存在常量区,const修饰的局部变量依然在栈上。程序代码区:存放源程序的二进制代码。
4.堆栈的对比
5.在Ubuntu、stm32下C程序分配地址的对比
6.对ARM Cortex-M/stm32F10x的存储器地址映射的理解
在ARM Cortex-M系列中,存储器地址映射通常遵循以下原则:
- 代码存储器: Flash存储器用于存储程序代码,通常被映射到处理器的地址空间的起始位置。该映射可以是连续的或分段的,取决于具体的处理器和片内存储器的布局。
- 数据存储器: 数据存储器包括SRAM(随机访问存储器)和外设寄存器,用于存储变量和外设的配置寄存器。SRAM通常映射到处理器地址空间的中间区域,而外设寄存器则映射到一个独立的地址空间,通常称为Peripherals区域。
- 堆栈: 堆栈用于存储函数调用的局部变量和返回地址等信息。在ARM Cortex-M系列中,堆栈位于SRAM的末尾,使用较高的地址。
- 特殊寄存器: ARM Cortex-M系列处理器还有一些特殊的寄存器,如NVIC(中断控制器)和SCB(系统控制块)。这些寄存器通常被映射到特定的地址,用于控制中断、系统时钟和处理器状态等。
stm32F10x系列单片机在ARM Cortex-M系列的基础上,还具有自己的存储器布局和外设寄存器映射。具体的映射关系和地址范围可以在芯片的参考手册中找到,手册会指定Flash、SRAM、寄存器和其他外设的起始地址和范围,以及访问这些地址时的读写权限和功能描述。
二、编程验证
1.Ubantu系统
- text.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] = "yaoyao";//栈 //定义常量字符串
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;}
- 输入指令:
gcc text.c -o text
./text
- 输出结果如下:
2.Keil stm32
- 新建工程text.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(72,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);
- 编译通过: