在嵌入式面试时volatile是必考题!

下面来解释一下volatile关键字的作用:

volatile关键字,是用于表明变量代码无法被优化!

比如:

int a = 0;
a = 1;
a = 2;
a = 3;

经过编译器代码优化后:

int a = 0;
a = 3;

省去重复工作,debug下不会作任何优化,但这样的代码效率一般只用在调试下,release模式下会对齐进行优化,在GCC的编译器下会直接对这段代码优化,GCC下没有debug和release模式!

这样的情况对,应用层来说可以解决重复代码,有效提高编码以及运行效率!

但是对于嵌入式开发就不一样了,每个电平对于不同的情况

GPIO_C |= (1<<5);
sleep(0xFFFFF);
GPIO_C |= (0<<5);

这段代码是让LED灯闪烁,但是倘若编译器为其进行了优化就会变成:

sleep(0xFFFFF);
GPIO_C |= (0<<5);

看不到闪烁的情况了,因为编译器觉得GPIO_C最终的结果会是 |= 0<<5,所以直接索性优化掉上面重复代码!

这样的话GPIO_C端口就接受不到高电平,也就无法驱动LED灯亮起,所以这样做是不对的!

所以我们要用到volatile关键,告诉编译器,无论如何都不要尝试对被volatile关键字声明的变量进行优化!

这样的话编译器就不会对齐变量进行优化!

volatile int a = 0;

即使是宏的情况下,编译器也一样会对其进行优化,所以我们要在宏定义里也加上volatile:

#define volatile  *(unsigned int*) 0x410000

这里在说说宏定义:

#define BLOCK_2_GPIOB_CRL      volatile  *(unsigned int*)BLOCK_2_APB2_GPIO_B+0x0    //BLOCK_2_APB2_GPIO_B = 0X100

在运用时

BLOCK_2_GPIOB_CRL |= 1

编译时会出现错误:表达式必须为左值

其实原因很简单,下面给大家看一下预编译文件:

volatile *(unsigned int*)0x100+0x0 |= 1

后面的0x100+0x0就错了!

编译器看成先对0x100地址取值,然后在加上0x0|=1

这样显然是错误的,0x0是立即数,也称为右值,无法赋值的!

所以我们要加上括号增加运算符优先级

 volatile *(unsigned int*)(BLOCK_2_APB2_GPIO_B+0x0)

预编译后:

volatile *(unsigned int*)(0x100+0x0) |= 1

这样编译器就会把0x100+0x0的地址里的值|=1

也就是将0x100这块内存地址的值赋予新的值,新值是0x100里的值|=1

因为上面用了赋值运算符=

volatile讲解与宏定义相关推荐

  1. 大牛深入浅出讲解C语言#define宏定义应用及使用方法

    在C语言中,我们使用#define来定义宏.在C程序编译的预处理阶段,预处理器会把宏定义的符号替换成指定的文本. 不带参数的宏 关于宏最常见的就是用来定义数值常量的名称,即没有参数的宏定义,采用如下形 ...

  2. 深入浅出讲解C语言#define宏定义应用及使用方法

    在C语言中,我们使用#define来定义宏.在C程序编译的预处理阶段,预处理器会把宏定义的符号替换成指定的文本. 不带参数的宏 关于宏最常见的就是用来定义数值常量的名称,即没有参数的宏定义,采用如下形 ...

  3. 宏定义 指针 c语言,C语言宏定义讲解(C和指针 笔记)

    关于C语言宏定义#define 最常用的莫过于通过宏定义定义常数了,例如 #define MAX 1000      通过宏定义程序中需要的常量,方便维护被多次引用的变量,并且宏替换在预处理阶段完成, ...

  4. C/C++常用宏定义,注意事项,宏中#和##的用法

    总结下宏和函数的不同之处,以供大家写代码时使用,这段总结摘自<C和指针>一书. 当然宏定义非常重要的,它可以帮助我们防止出错,提高代码的可移植性和可读性等. 下面列举一些成熟软件中常用得宏 ...

  5. Linux 内核中的宏定义

    Linux 内核中的宏定义 rtoax 日期 内核版本:linux-5.10.13 注释版代码:https://github.com/Rtoax/linux-5.10.13 __attribute__ ...

  6. C语言~宏操作大全(宏定义、内置宏、__FILE__、__LINE__、##用法)

    当然宏定义非常重要的,它可以帮助我们防止出错,提高代码的可移植性和可读性等.下面列举一些成熟软件中常用得宏定义1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDE ...

  7. C语言宏定义使用技巧

    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等.下面列举一些成熟软件中常用得宏定义...... 1,防止一个头文件被重复包含 #ifndef COMDEF_H ...

  8. c语言宏定义_掌握C语言,中文编程不是梦

    文/Edward 前面我们在讲节程序编译的时候,编译器做的第一步就是预处理.C语言的预处理,其实是编译器在对整个工程编译之前做的一些文本性质的工作,例如我们经常使用的#include,这就是一个典型的 ...

  9. linux中offsetof与container_of宏定义

    linux内核中offsetof与container_of的宏定义 #define offsetof(TYPE, MEMBER)    ((size_t) &((TYPE *)0)->M ...

最新文章

  1. JBoss5.1.0部署SSH2
  2. 【软考-软件设计师】解释程序实现高级语言的三种方式
  3. hdu5468 Puzzled Elena
  4. 解决VS'scanf':this function or variable may be unsafe.`(VS安全函数问题)
  5. Spark下的word2vec模型训练
  6. 坦克大战-C语言-详注版
  7. 2021高考成绩查询省排名,【重磅整理】2021全国各地高考预测分数线出炉,这样估分可以估算全省排名...
  8. 小白 C 入门并发疯学习路线(书单)
  9. 卡巴斯基:揭开“火焰”病毒(Flame)的神秘面纱
  10. cmd链接php mysql数据库_php连接mysql数据库_cmd连接mysql数据库 - MySQL最新手册教程 - php中文网手册...
  11. MATLAB中的转置 和 复数的共轭转置
  12. 计算机考研用python_20年苏州大学计算机考研经验
  13. EasyClick 易点云测
  14. centos6 yum安装nginx
  15. 赋能数字化生命力,让企业未来焕发青春
  16. 微信公众号基础04_分享和录音功能的实现
  17. 人生=亲情+爱情+金钱+理想+友情?
  18. mac下使用diskutil给U盘格式化
  19. 无法打开模块文件“C:\Users\fkg\AppData\Local\Temp\.NETFramework,Version=v4.5.AssemblyAttributes.vb”系统找不到指定文件
  20. python实现直方图、条形图、折线图、饼图(参数详情)

热门文章

  1. windows脚本bat批处理 关闭显示器 关闭显示器脚本bat
  2. 我国常用的微型计算机是,2013云南省全国计算机等级考试二级笔试试卷VB理论考试试题及答案...
  3. sql重复数据只保留一条_一条SQL完成跨数据库实例Join查询
  4. r语言 悲观剪枝_R语言实战(5) ——高级数据管理
  5. phpcms 指定id范围 调用_Dubbogo 源码笔记(二)客户端调用过程
  6. 螺旋传动设计系统lisp_[罗升机电]第236期 丝杆升降机系统工程之齿轮传动的设计!...
  7. json接口文档模板_在.Net Core WebAPI下给Swagger增加导出离线文档功能
  8. python程序变量名_python 变量名的规范
  9. mysql 补丁 patch6_系统管理-第6部分――补丁(patch)管理和在线更新
  10. linux 无线 扫描不到网络,在Ubuntu笔记本上搜不到无线信号的解决办法