重温C语言程序

重温C语言程序

在ubuntu系统中编程C语言程序全局变量、局部变量、堆、栈,并在不同环境验证

一,概念

(一)stm32的堆、栈、全局变量的分配地址编程显示
在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着data段。
1)、栈区(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)、代码区
程序执行代码存放在代码区。
字符串常量也有可能存放在代码区
(二)待验证的概念与结论
c程序的执行也就是静态的文件加载到内存下的过程,内存属性有两种,如下所示:
静态分配内存:是在程序编译和链接时就确定好的内存。
动态分配内存:是在程序加载、调入、执行的时候分配/回收的内存
栈的地址是向下增长
堆的地址是向上增长
静态变量是地址向下增长
全局常量是地址向上增长
函数的地址向上增长
而由函数,一直到栈区,地址总体是从低地址到高地址,逐步递增的。

二,ubuntu系统中编程,输出信息进行验证

(一)打开ubuntu,编写一个.c文件,代码如下:

#include <stdio.h>
#include <stdlib.h>
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main( )
{   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);
    return 0;
}

(二)编译

执行结果可以验证上述结论。

三,在Keil中针对stm32系统进行编程

(一)在keil中对程序进行改写(程序于野火官网下载)

将main.c修改如下:

#include "stm32f10x.h"
#include "bsp_usart.h"

char global1[16];
char global2[16];
char global3[16];
	
int main(void)
{	
  char part1[16];
  char part2[16];
  char part3[16];

  USART_Config();

  printf("part1: 0x%p\n", part1);
  printf("part2: 0x%p\n", part2);
  printf("part3: 0x%p\n", part3);
	 
  printf("global1: 0x%p\n", global1);
  printf("global2: 0x%p\n", global2);
  printf("global3: 0x%p\n", global3);
  while(1)
	{	
		
	}	
}

(二)编译并把HEX文件烧进芯片
(1)编译,烧录

(2)观察结果,验证

part1、part2、part3为栈中的局部变量,地址逐渐减小。
global1、global2、global3为静态区中的全局变量,地址逐渐增加
(三)修改代码,继续验证
(1)对于main.c代码进行修改如下:

#include "stm32f10x.h"
#include "bsp_usart.h"
#include <stdlib.h>

int main(void)
{	
  static char st1[16];
  static char st2[16];
  static char st3[16];
  char *p1;
  char *p2;
  char *p3;

 
  USART_Config();

  printf("st1: 0x%p\n", st1);
  printf("st2: 0x%p\n", st2);
  printf("st3: 0x%p\n", st3);
	 
  p1 = (char *)malloc(sizeof(char) * 16);
  p2 = (char *)malloc(sizeof(char) * 16);
  p3 = (char *)malloc(sizeof(char) * 16);
	
  printf("p1: 0x%p\n", p1);
  printf("p2: 0x%p\n", p2);
  printf("p3: 0x%p\n", p3);
  while(1)
	{	
		
	}	
}


定义静态变量和指针,并返回它们的地址给上位机。
(2)重复上面的操作继续验证


st1、st2、st3都是静态变量,他们的地址依次增加。
p1、p2、p3是堆中的指针,他们的地址也是依次增加。
总结
本次实验复习了C的一些基本概念,在C\C++中,通常可以把内存理解为4个分区:栈、堆、全局/静态存储区和常量存储区。
1 内存栈区stack: 存放局部变量名;
2. 内存堆区heap: 存放new或者malloc出来的对象;
3. Text & Data & Bss:代码段与静态分配
4. BSS区(未初始化数据段):并不给该段的数据分配空间,仅仅是记录了数据所需空间的大小。
5.DATA(初始化的数据段):为数据分配空间,数据保存在目标文件中。
还用Ubuntu和芯片成功验证,温故而知新,我获益匪浅。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值