完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

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

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

9.1 初学者重要提示

9.2 数据类型

9.3 局部变量和全局变量

9.4 堆栈

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

9.6 总结

9.1   初学者重要提示

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

论坛下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=91219。

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

http://www.armbbs.cn/forum.php?mod=viewthread&tid=15408 。

9.2   数据类型

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

9.2.1      ANSI C和ISO C历史

  1. 1983年,美国国家标准协会(ANSI)组成了一个委员会来创立C语言的标准。因为这个标准是1989年发布的,所以一般简称C89标准。有些人也把C89标准叫做ANSI C。
  2. 在1990年,ANSI C89标准被国际标准化组织(ISO)和国际电工委员会(IEC)采纳为国际标准,名叫ISO/IEC 9899:1990 - Programming languages  C,有些人简称C90标准。因此,C89和C90通常指同一个标准,一般更常用C89这种说法。
  3. 在2000年3月,国际标准化组织(ISO)和国际电工委员会(IEC)采纳了第二个C语言标准,名叫ISO/IEC 9899:1999 - Programming languages -- C,简称C99标准。
  4. 在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   signed          char int8_t;

typedef   signed short     int int16_t;

typedef   signed           int int32_t;

typedef   signed       __INT64 int64_t;

/* exact-width unsigned integer types */

typedef unsigned          char uint8_t;

typedef unsigned short     int uint16_t;

typedef unsigned           int uint32_t;

typedef unsigned       __INT64 uint64_t;

/* 7.18.1.2 */

/* smallest type of at least n bits */

/* minimum-width signed integer types */

typedef   signed          char int_least8_t;

typedef   signed short     int int_least16_t;

typedef   signed           int int_least32_t;

typedef   signed       __INT64 int_least64_t;

/* minimum-width unsigned integer types */

typedef unsigned          char uint_least8_t;

typedef unsigned short     int uint_least16_t;

typedef unsigned           int uint_least32_t;

typedef unsigned       __INT64 uint_least64_t;

/* 7.18.1.3 */

/* fastest minimum-width signed integer types */

typedef   signed           int int_fast8_t;

typedef   signed           int int_fast16_t;

typedef   signed           int int_fast32_t;

typedef   signed       __INT64 int_fast64_t;

    /* fastest minimum-width unsigned integer types */

typedef unsigned           int uint_fast8_t;

typedef unsigned           int uint_fast16_t;

typedef unsigned           int uint_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的标准写法来定义整数。

  •   知识点拓展

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

http://www.armbbs.cn/forum.php?mod=viewthread&tid=501

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 = ;           //全局初始化区, 可以被其他c文件 extern 引用

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

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

int main(void)

{

     uint32_t b;             //栈

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

     uint8_t *p2;            //栈

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

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

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

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

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

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

}

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

Symbol Name                      Value        Ov Type        Size    Object(Section)

a                               0x20000000     Data                     main.o(.data)

p1                              0x2000000c     Data                     main.o(.data)

ss                              0x20000004     Data                     main.o(.data)

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

9.6   总结

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

【STM32H7教程】第9章 STM32H7重要知识点数据类型,变量和堆栈的更多相关文章

  1. C# 图解教程 第三章 类型、存储和变量

    类型.存储和变量 C#程序是一组类型声明类型是一种模板实例化类型数据成员和函数成员预定义类类型用户定义类型栈和堆 栈堆 值类型和引用类型 存储引用类型对象的成员C#类型的分类 变量静态类型和dynam ...

  2. 【STM32H7教程】第13章 STM32H7启动过程详解

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第13章       STM32H7启动过程详解 本章教 ...

  3. 【STM32H7教程】第12章 STM32H7的HAL库框架设计学习

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第12章       STM32H7的HAL库框架设计学 ...

  4. 【STM32H7教程】第10章 STM32H7的FLASH,RAM和栈使用情况(map和htm文件)

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第10章       STM32H7的FLASH,RAM ...

  5. 【STM32H7教程】第8章 STM32H7的终极调试组件Event Recorder

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第8章   STM32H7的终极调试组件Event Re ...

  6. 【STM32H7教程】第3章 STM32H7整体把控

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第3章   STM32H7整体把控 初学STM32H7一 ...

  7. 【STM32H7教程】第14章 STM32H7的电源,复位和时钟系统

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第14章       STM32H7的电源,复位和时钟系 ...

  8. 【STM32H7教程】第23章 STM32H7的MPU内存保护单元(重要)

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第23章       STM32H7的MPU内存保护单元 ...

  9. 【STM32H7教程】第31章 STM32H7的USART应用之RS485

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第31章       STM32H7的USART应用之RS48 ...

随机推荐

  1. SOFA 源码分析 —— 服务引用过程

    前言 在前面的 SOFA 源码分析 -- 服务发布过程 文章中,我们分析了 SOFA 的服务发布过程,一个完整的 RPC 除了发布服务,当然还需要引用服务. So,今天就一起来看看 SOFA 是如何引 ...

  2. C语言可变参数va_list

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,-) int ...

  3. python+selenium实现登录账户

    selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium Remote Control)和测试的并行处理(Selenium Gr ...

  4. 10个Python练手小程序,学习python的很好的资料

    [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去  掉不满足条件的排列 ...

  5. EXCEL解析之终极方法WorkbookFactory

    Selenium做自动化测试当然不能避免和Excel打交道. 由于Excel版本的关系,文件扩展名分xls和xlsx, 以往的经验都是使用HSSFWorkbook和XSSFWorkbook来分别处理. ...

  6. Java 8 文件操作(转)

    我们知道在JDK6甚至之前的时候,我们想要读取一个文本文件也是非常麻烦的一件事,而现在他们都变得简单了, 这要归功于NIO2,我们先看看之前的做法: 读取一个文本文件 BufferedReader b ...

  7. CentOS6.5系统挂载NTFS分区的硬盘

    下载rpmforge,下载对应的版本,就是对应CentOS版本,还有32位与64位也要对应上.rpmforge拥有4000多种CentOS的软件包,被CentOS社区认为是最安全也是最稳定的一个软件仓 ...

  8. Unity文档阅读 第三章 依赖注入与Unity

    Introduction 简介In previous chapters, you saw some of the reasons to use dependency injection and lea ...

  9. py文件转换为exe文件

    遇到这个问题时在网上找了一会资料,很多博客的方法很旧了,介绍一种最简单的,pyinstaller. 时间比较早的资料还在介绍如何安装pip(python的包管理器),其实python中已经自带pip了 ...

  10. ORACLE 快速启动监听及相关服务程序

    windows7 系统下,鼠标移至任务栏右键启动任务管理器->选择服务->点击右下角服务选项 ->选中名称,键盘输入O(大写),快速找到ORACLE相关服务进程 ->将所有的O ...