第9章   STM32H7重要知识点数据类型,变量和堆栈

本章教程为大家介绍数据类型,变量和堆栈的相关知识。

9.1 初学者重要提示

9.2 数据类型

9.3 局部变量和全局变量

9.4 堆栈

9.5 局部变量,全局变量和堆栈实例

9.6 总结

9.1   初学者重要提示

1、 如果对C语言不熟练的话,可以阅读C语言书:C Primer Plus(第五版)中文版.pdf

2、 为了更好的学习本章知识点,可以看之前做的视频教程第10章,针对H7也将在今年发布视频教程:

9.2   数据类型

了解数据类型之前要对ANSI C和ISO C的发展史有个了解,特别是C89,C99和C11的由来。

9.2.1      ANSI C和ISO C历史

1983年,美国国家标准协会(ANSI)组成了一个委员会来创立C语言的标准。因为这个标准是1989年发布的,所以一般简称C89标准。有些人也把C89标准叫做ANSI C。

在1990年,ANSI C89标准被国际标准化组织(ISO)和国际电工委员会(IEC)采纳为国际标准,名叫ISO/IEC 9899:1990 - Programming languages  C,有些人简称C90标准。因此,C89和C90通常指同一个标准,一般更常用C89这种说法。

在2000年3月,国际标准化组织(ISO)和国际电工委员会(IEC)采纳了第二个C语言标准,名叫ISO/IEC 9899:1999 - Programming languages -- C,简称C99标准。

在2011年12月,国际标准化组织(ISO)和国际电工委员会(IEC)采纳了第三个C语言标准,名叫ISO/IEC 9899:2011 - Information technology -- Programming languages -- C,简称C11标准。它是C程序语言的最新标准。

对于我们常用的编译器MDK和IAR而已,C89,C99和C11均支持。

9.2.2      ARM架构(含Cortex-M系列)数据类型

ARM架构(含Cortex-M系列)的数据类型定义如下:

9.2.3      头文件stdint.h对数据类型的定义

stdint.h是C99中引进的一个标准C库的头文件。目前大部分单片机C编译器均支持,IAR和MDK都支持。下面是部分内容(来自MDK)。

/*exact-width signed integer types*/typedef signedcharint8_t;

typedef signedshort intint16_t;

typedef signedintint32_t;

typedef signed __INT64 int64_t;/*exact-width unsigned integer types*/typedef unsignedcharuint8_t;

typedef unsignedshort intuint16_t;

typedef unsignedintuint32_t;

typedef unsigned __INT64 uint64_t;/*7.18.1.2*/

/*smallest type of at least n bits*/

/*minimum-width signed integer types*/typedef signedcharint_least8_t;

typedef signedshort intint_least16_t;

typedef signedintint_least32_t;

typedef signed __INT64 int_least64_t;/*minimum-width unsigned integer types*/typedef unsignedcharuint_least8_t;

typedef unsignedshort intuint_least16_t;

typedef unsignedintuint_least32_t;

typedef unsigned __INT64 uint_least64_t;/*7.18.1.3*/

/*fastest minimum-width signed integer types*/typedef signedintint_fast8_t;

typedef signedintint_fast16_t;

typedef signedintint_fast32_t;

typedef signed __INT64 int_fast64_t;/*fastest minimum-width unsigned integer types*/typedef unsignedintuint_fast8_t;

typedef unsignedintuint_fast16_t;

typedef unsignedintuint_fast32_t;

typedef unsigned __INT64 uint_fast64_t;

以MDK5.26为例,stdint.h位于如下路径:

\Keil_v526\ARM\ARMCC\include

以IAR8.X为,stdint.h位于如下路径:

\IAR Systems\Embedded Workbench 8.1\arm\inc\c

9.2.4      程序中推荐的变量命名方式

看程序的时候,经常会看到各种各样的变量命名方式,例如声明一个8位无符号整数,常见的有如下几种写法:

u8 err;

U8 err;

INT8U err;

UINT8 err;

uint8 err;

uint8_t err;

当大家阅读别人写的程序时,往往会看到风格各异的定义方式,移植部分程序时也不知道采用哪种方式更合适。

我们推荐大家采用最后一种定义方式,这种方法符合C99规范,ST的固件库都是采用的这种类型定义方式。像我们开发板配套的STM32例程,从2009年最初的版本开始就一直沿用C99的标准写法来定义整数。

知识点拓展

针对变量声明问题,之前专门发过一个详细的帖子:

9.3   局部变量和全局变量

9.3.1      局部变量

在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的,这称为局部变量。

使用局部变量注意以下问题:

不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。

形式参数也是局部变量。

局部变量的作用域在函数内部。

9.3.2      全局变量

在函数内部定义的变量是局部变量,而在函数之外定义的变量称为外部变量,也就是全局变量。使用全局变量的注意事项:

全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。

设置全局变量的作用是增加了函数间数据联系的渠道。

如果在同一个源文件中,外部变量和局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即外部变量将不起作用。

9.3.3      使用全局变量的缺点

程序设计中,建议不要创建太多的全局变量,主要是出于以下三点考虑:

全局变量在程序的执行过程中都占用存储单元,而不是仅在需要时才占用存储单元。

函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移植到另一个文件中,还要将有关的外部变量及其值一起移植过去。

使用全局变量过多,会降低程序的清晰性,特别是多个函数都调用此变量时。

9.3.4      变量的存储类别

从变量的作用域来分,可以分为全局变量和局部变量,而从变量值存在的时间来看,可以分为静态存储方式和动态存储方式。

静态存储方式:指在程序运行期间由系统分配固定的存储空间方式。

动态存储方式:在程序运行期间根据需要进行动态的分配存储空间方式。

全局变量存储在静态存储区中,动态存储区可以存放以下数据:

函数形式参数,在调用函数时给形参分配存储空间。

局部变量(未加static声明的局部变量)。

函数调用时的现场保护和返回地址等。

9.3.5      用static声明局部或者全局变量

有时候希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即占用的存储单元不释放,在下一次该函数调用时,该变量已有值,就是上一次函数调用结束时的值。这时可以使用关键字static进行声明。

用static声明一个变量的作用:

对局部变量用static声明,则使用该变量在整个程序执行期间不释放,为其分配的的空间始终存在。

全局变量用static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)。

9.4   堆栈

9.4.1      堆栈作用

栈(stack)空间,用于局部变量,函数调时现场保护和返回地址,函数的形参等。

堆(heap)空间,主要用于动态内存分配,也就是说用 malloc,calloc, realloc等函数分配的变量空间是在堆上。以STM32H7为例,堆栈是在startup_stm32h743xx.s文件里面设置:

9.4.2      寄存器组(堆栈指针寄存器)

Cortex – M7/M4/M3 处理器拥有R0-R15的通用寄存器组。其中R13作为堆栈指针SP。SP有两个,但在同一时刻只能有一个可以用。

主堆栈指针(MSP):这是缺省的堆栈指针,它由OS内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。

进程堆栈指针(PSP):用于常规的应用程序代码(不处于异常服务例程中时)。

另外以下两点要注意:

大多数情况下的应用,只需使用指针MSP,而PSP多用于 RTOS 中。

R13 的最低两位被硬线连接到0,并且总是读出0,这意味着堆栈总是4字节对齐的。

9.4.3      Cortex-M7/M4/M3向下生长的满栈

这个知识点在以后用H7移植RTOS时,非常有用。

9.4.4      堆栈的基本操作

这里对入栈和出栈做个简单的介绍。PUSH入栈操作:SP先自减 4,再存入新的数值:

POP出栈操作:先从SP指针处读出上一次被压入的值,再把SP指针自增 4:

9.5   局部变量,全局变量和堆栈实例

通过下面的实例可以对局部变量,全局变量和堆栈有个感性的认识:

uint32_t a = 0; //全局初始化区, 可以被其他c文件 extern 引用

static uint32_t ss = 0; //静态变量,只允许在本文件使用

uint8_t*p1; //全局未初始化区

int main(void)

{

uint32_t b;//栈

uint8_t s[]= "abc"; //栈

uint8_t*p2; //栈

uint8_t*p3 = "123456"; //123456\0在常量区,p3在栈上。

static uint32_t c =0; //全局(静态)初始化区

p1= (uint8_t *)malloc(10); //在堆区申请了10个字节空间

p2= (uint8_t *)malloc(20); //在堆区申请了20个字节空间

strcpy(p1,"123456"); /*123456字符串(结束符号是0(\0),总长度7)放在常量区,

编译器可能会将它与p3所指向的"123456"优化成一个地方*/}

通过查看MAP文件,可以看全局变量在RAM中的位置:

Symbol Name Value Ov Type Size Object(Section)

a0x20000000 Data 4main.o(.data)

p10x2000000c Data 4main.o(.data)

ss0x20000004 Data 4 main.o(.data)

而局部变量要调整状态进入main函数里面查看:

9.6   总结

C语言的基础知识点要掌握牢靠,对于后面学习HAL库源码大有裨益。

stm32h7内存分配_【STM32H7教程】第9章 STM32H7重要知识点数据类型,变量和堆栈...相关推荐

  1. stm32h7内存分配_【STM32H7教程】第26章 STM32H7的TCM,SRAM等五块内存的超方便使用方式...

    第26章       STM32H7的TCM,SRAM等五块内存的超方便使用方式 本章教程为大家分享一种快捷的DTCM,SRAM1,SRAM2,SRAM3和SRAM4的使用方式.MDK和IAR均支持这 ...

  2. stm32h7内存分配_【STM32H7教程】第25章 STM32H7的TCM,SRAM等五塊內存基礎知識

    第25章       STM32H7的TCM,SRAM等五塊內存基礎知識 本章教程為大家介紹STM32H7帶的ITCM,DTCM,AXI SRAM,SRAM1,SRAM2,SRAM3,SRAM4和備份 ...

  3. stm32h7内存分配_stm32h7“分散加载方式管理多块内存”

    默认情况下,我们都是通过 MDK 的 option 选项设置 Flash 和 RAM 大小,如图1 图1 这种情况下,不方便用户将变量定义到指定的 CCM 或者 SDRAM 中.而使用attribut ...

  4. java虚拟机手动内存分配_《深入理解java虚拟机》-垃圾收集器与内存分配策略

    如何判断对象已死? 引用计数算法 在对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1:当引用失效时,计数器减1:其中计数器为0的对象是不可能再被使用的已死对象. 引用计数算法的实现很简单 ...

  5. java 继承的内存分配_图解Java继承内存分配

    继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法. (3)子类中定义的成员变量和父类中定义 ...

  6. spark executor内存分配_二十二、Spark之图解Executor端内存管理

    Spark应用程序执行时,Spark集群会启动Driver和Executor两种JVM进程,Driver端负责创建SparkContext上下文(通往集群的唯一通道),构建DAG, 创建Task并进行 ...

  7. linux 优化内存分配,Linux性能优化 第三章 性能工具:系统内存

    3.1内存性能统计信息 3.1.1内存子系统和性能 和CPU相比,内存的读写速度都大大落后于CPU.为了弥补这个差距,通常CPU会采用高速缓存的机制(高cache). 3.1.2内存子系统(虚拟存储器 ...

  8. C语言的变量的内存分配

    今晚看了人家写的一个关于C语言内存分配的帖子,发现真是自己想找的,于是乎就收藏了... 先看一下两段代码: char* toStr() {char *s = "abcdefghijkl&qu ...

  9. javascript中变量的内存分配,以及const VS let

    作为前端开发者,我们每天都在初始化数不尽的变量.js中有基础数据和引用数据,那么他们是在js内存中是如何分配的呢?如果是初级开发者,可能对此有些模糊不清,那么接下来可以了解下关于变量内存分配,以及co ...

最新文章

  1. python 归一化_几种归一化方法(Normalization Method)python实现
  2. python pywin32 微信_python win32con安装_python-2.7 – 安装pywin32
  3. metaprogramming笔记
  4. Mysql 添加用户 授权等操作
  5. opencv 轮廓检测
  6. Ubuntu安装Python2.7,nodejs,Redis
  7. QA:golang redis协议同时写入报错
  8. PS选中部分区域调整透明度
  9. 【C语言基础学习笔记】一、初始C语言(2)
  10. GoLang读写数据---上
  11. 织梦dedeCMS留言薄
  12. pcm数据编码成为aac格式文件(可以在酷狗播放)
  13. 技术人员的狂欢 | 看雪2020第四届安全开发者峰会顺利落幕
  14. 开源网络准入软件packetfence 部署心得-1
  15. 分享软件测试实习生的第一天~
  16. 基于stm32的智能语音提醒器
  17. #软件设计模式#桥接模式#小黑的学习笔记
  18. 乘法原理的例题和答案_加法原理与乘法原理练习题
  19. wireshark抓组播数据_wireshark过滤?wireshark 看端口号?wireshark组播包?WireShark 过滤语法...
  20. Oracle——删除用户以及用户下数据

热门文章

  1. gta5为什么显示更新无法连接服务器,gta5无法更新服务器
  2. 夜思 | 听说你单身?“替代性恋爱”了解一下
  3. SVG进阶-sprite 雪碧图
  4. Sprite和Texture的区别
  5. 基于改进正弦余弦算法的函数寻优算法
  6. 情感分类模型介绍CNN、RNN、LSTM、栈式双向LSTM
  7. Angular在页面加载很慢的时候,会出现双花括号的问题
  8. 11月29日做题截图
  9. SAP ABAP 解析 excel 文件的函数 TEXT_CONVERT_XLS_TO_SAP 单步执行分析
  10. 指令下载Google网盘数据遇到的无法连接问题