目录
一、c语言内存地址
C语言程序里全局变量、局部变量、堆、栈的内存地址
c语言中内存分为以下区域
区域 | 作用 |
---|---|
内存栈区 | 存放局部变量名 |
内存堆区 | 存放new或者malloc出来的对象 |
常数区 | 存放局部变量或者全局变量的值 |
静态区 | 用于存放全局变量或者静态变量 |
而一个c语言程序通常要占用的内存为
-
1、栈区(stack): 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
-
2、堆区(heap) : 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
-
3、全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
-
4、文字常量区 :常量字符串就是放在这里的。 程序结束后由系统释放
-
5、程序代码区:存放函数体的二进制代码。
二、在ubuntu系统中编程,对输出信息进行验证
此项目所使用的代码为
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void before()
{
}
char g_buf[16];
char g_buf2[16];
char g_buf3[16];
char g_buf4[16];
char g_i_buf[]="123";
char g_i_buf2[]="123";
char g_i_buf3[]="123";
void after()
{
}
int main(int argc, char **argv)
{
char l_buf[16];
char l_buf2[16];
char l_buf3[16];
static char s_buf[16];
static char s_buf2[16];
static char s_buf3[16];
char *p_buf;
char *p_buf2;
char *p_buf3;
p_buf = (char *)malloc(sizeof(char) * 16);
p_buf2 = (char *)malloc(sizeof(char) * 16);
p_buf3 = (char *)malloc(sizeof(char) * 16);
printf("g_buf: 0x%x\n", g_buf);
printf("g_buf2: 0x%x\n", g_buf2);
printf("g_buf3: 0x%x\n", g_buf3);
printf("g_buf4: 0x%x\n", g_buf4);
printf("g_i_buf: 0x%x\n", g_i_buf);
printf("g_i_buf2: 0x%x\n", g_i_buf2);
printf("g_i_buf3: 0x%x\n", g_i_buf3);
printf("l_buf: 0x%x\n", l_buf);
printf("l_buf2: 0x%x\n", l_buf2);
printf("l_buf3: 0x%x\n", l_buf3);
printf("s_buf: 0x%x\n", s_buf);
printf("s_buf2: 0x%x\n", s_buf2);
printf("s_buf3: 0x%x\n", s_buf3);
printf("p_buf: 0x%x\n", p_buf);
printf("p_buf2: 0x%x\n", p_buf2);
printf("p_buf3: 0x%x\n", p_buf3);
printf("before: 0x%x\n", before);
printf("after: 0x%x\n", after);
printf("main: 0x%x\n", main);
if (argc > 1)
{
strcpy(l_buf, argv[1]);
}
return 0;
}
其中
g_buf是定义在主函数外的全局变量
l_bur是定义的一个栈
s_buf是定义的一个静态变量
p_buf是分配的到的堆区
输出的结果为
从输出结果可以看出:
栈的地址是从上向下增长
堆的地址是从下向上增长
静态变量的地址是从下向上增长
函数的地址是从下向上增长
三、对stm32系统进行编程,调试变量, 通过串口输出信息到上位机,进行验证
在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。
总的分布如下所示:
内存高地址 | 栈区 |
---|---|
堆区 | |
.bss段 | |
.data段 | |
常量区 | |
内存低地址 | 代码区 |
这里使用了野火指南者开发板的库函数来辅助实现功能
#include "stm32f10x.h"
#include "bsp_usart.h"
#include <stdio.h>
#include <stdlib.h>
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main( )
{
USART_Config();
Usart_SendString( DEBUG_USARTx,"ÕâÊÇÒ»¸ö´®¿ÚÖжϽÓÊÕ»ØÏÔʵÑé\n");
while(1)
{
static int m1=2, m2;
int i = 1;
char *p;
char str[10] = "hello";
char *var1 = "123456";
char *var2 = "abcdef";
int *p1=malloc(4);
int *p2=malloc(4);
free(p1);
free(p2);
printf("栈区-变量地址\n");
printf(" i:%p\n", &i);
printf(" p:%p\n", &p);
printf(" str:%p\n", str);
printf("\n堆区-动态申请地址\n");
printf(" %p\n", p1);
printf(" %p\n", p2);
printf("\n.bss段\n");
printf("全局外部无初值 k2:%p\n", &k2);
printf("静态外部无初值 k4:%p\n", &k4);
printf("静态内部无初值 m2:%p\n", &m2);
printf("\n.data段\n");
printf("全局外部有初值 k1:%p\n", &k1);
printf("静态外部有初值 k3:%p\n", &k3);
printf("静态内部有初值 m1:%p\n", &m1);
printf("\n常量区\n");
printf("文字常量地址 :%p\n",var1);
printf("文字常量地址 :%p\n",var2);
printf("\n代码区\n");
printf("程序区地址 :%p\n",&main);
}
}
将上述代码进行编译后可以得到像下图的几个参数。
Code就是代码占用大小,RO-data是只读常量、RW-data是已初始化的可读可写变量,ZI-data是未初始化的可读可写变量。
通过串口调试程序可以看到输出为
可以发现栈的地址值是从上向下减小的,堆的地址则是从上到下增长的。
四、参考资料
【IoT】STM32 内存分配详解
基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM
STM32 KEIL下的堆栈设置