C语言学习及应用笔记之四:C语言volatile关键字及其使用
在C语言中,还有一个并不经常使用但却非常有用的关键字volatile。那么使用volatile关键字究竟能干什么呢?接下来我将就此问题进行讨论。
一个使用volatile关键字定义变量,其实就是告诉编译系统这变量可能会被意想不到地改变。那么编译时,编译器就不会自作主张的去假设这个变量的值,而进行代码的优化了。确切的说就是,编译器在编译代码时,优化器每次遇到这个变量,都会到内存中重新读取,而不会使用保存在寄存器里的备份来对代码进行优化。
我们已经了解了volatile关键字的基本作用。那么,在什么情况下使用volatile关键字呢?一般说来,在如下的几种情况通常会使用volatile关键字:
- 在中断服务程序中修改的,供其它程序检测的变量,通常需要定义为volatile;
- 在多任务环境下,各任务间共享的标志,通常也需要定义为volatile;
- 存储器映射的硬件寄存器通常也需要定义为volatile,因为每次对它的读写都可能有不同意义;
(1)使用中断改变对象值的情况
我们在中断服务程序中操作了某个对象,比如谁改变了一个变量的值。而在其它程序中我们希望通过这个变量值得改变去进行一些操作。在这个时候,我们使用或者不使用volatile关键字,可能得到截然不同的结果。
如果我们将变量定义为:static int var=0; ,然后再中断服务成勋中将其修改为:var=1,但是在另一函数中使用它但不会修改它,那么编译器会认为它没有变化,从而直接使用寄存器中的副本。
如果我们将变量定义为:volatile int var=0;,那么结果就完全不同了,每次在函数中使用var变量时,都会重新读取,而不会使用寄存器中的副本。
(2)多任务共享标志的情况
多任务共享时,其实也是一样的,在一个任务中修改了一个对象后,在另一个对象中应用它,但编译器并没发现在该任务中对它有修改。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。从而并不能响应在另一任务下的变化。
在这种情况下,一般我们都需要使用volatile关键字来定义任务间共享的标识。
(3)硬件寄存器内存映射的情况
内存映射的情况是非常多的,比如我们将外设的寄存器映射到内存的某一段区域;再比如我们同过DMA方式将数据直接写到内存中的某一段区域。
由于我们外部的数据都是直接进入了内存区域,而程序知识引用它的值。编译器优化时可能就直接采用寄存器中的副本了。佷显然这不是我们需要的结果,这时将这段内存对应的变量声明为volatile,则可以保证我们的需求。
综上所述,我们说明了volatile关键字的常规用法。当然,我们也可以发现volatile关键字是会降低编译器优化力度的,但它却可以保证程序的正确性,所以在适合的地方使用volatile关键字是必要的。不过能不能用的好,还要看编程者的基本功。
欢迎关注:

C语言学习及应用笔记之四:C语言volatile关键字及其使用的更多相关文章
- C语言学习及应用笔记之一:C运算符优先级及使用问题
C语言中的运算符绝对是C语言学习和使用的一个难点,因为在2011版的标准中,C语言的运算符的数量超过40个,甚至比关键字的数量还要多.这些运算符有单目运算符.双目运算符以及三目运算符,又涉及到左结合和 ...
- GO语言学习(十六)Go 语言结构体
Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...
- C语言学习书籍推荐《C程序设计语言(第2版•新版)》下载
克尼汉 (作者), 等 (作者, 译者), 徐宝文 (译者) 下载地址:点我 <C程序设计语言(第2版•新版)>是由C语言的设计者Brian W.Kernighan和Dennis M.Ri ...
- C语言学习及应用笔记之七:C语言中的回调函数及使用方式
我们在使用C语言实现相对复杂的软件开发时,经常会碰到使用回调函数的问题.但是回调函数的理解和使用却不是一件简单的事,在本篇我们根据我们个人的理解和应用经验对回调函数做简要的分析. 1.什么是回调函数 ...
- C语言学习及应用笔记之五:C语言typedef关键字及其使用
在C语言中有一个typedef关键字,其用来定义用户自定义类型.当然,并不是真的创造了一种数据类型,而是给已有的或者符合型的以及复杂的数据类型取一个我们自己更容易理解的别名.总之,可以使用typede ...
- C语言学习及应用笔记之三:C语言const关键字及其使用
在C语言程序中,const关键字也是经常会用到的一个关键字,那么使用const关键字的目的是什么呢?事实上,在程序中使用const关键字的主要目的就是为了向使用者传递设计者的一些意图. 事实上,无论我 ...
- C语言学习及应用笔记之二:C语言static关键字及其使用
C语言有很多关键字,大多关键字使用起来是很明确的,但有一些关键字却要相对复杂一些.我们这里要说明的static关键字就是如此,它的功能很强大,相应的使用也就更复杂. 一般来说static关键字的常见用 ...
- C语言学习及应用笔记之六:C语言extern关键字及其使用
在C语言中,修饰符extern用在变量或者函数的声明前,用来以标识变量或者函数的定义在别的文件中,提示编译器遇到此变量或者函数时,在其它文件中寻找其定义.extern关键字的用法有几种,我们下面对其进 ...
- 从零开始学习SSH框架笔记之四 几个关键配置文件备忘(模板)
不多说,直接上代码.关于注释我尽量写详细点. 1.web.xml <?xml version="1.0" encoding="UTF-8"?> &l ...
随机推荐
- H5调用手机拍照并展示在前端页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- fetch和axios获取数据
fetch("/api/goods") .then(res => { return res.json(); }) .then(response => { console ...
- php如何解决中文乱码问题?
为什么会出现中文乱码? 很多新手朋友学习PHP的时候,发现程序中的中文在输出的时候会出现乱码的问题,那么为什么会出现这种乱码的情况呢?一般来说,乱码的出现有2种原因,一种是由于编码(charset) ...
- js 实现数据结构 -- 队列
原文: 在 Javascript 中学习数据结构与算法. 概念: 与栈相反,队列是一种遵循先进先出 (FIFO / First In First Out) 原则的一组有序的项:队列在尾部添加新元素,并 ...
- 从备份文件bak中识别SQL Server的版本
SQLServer 的备份文件是以.bak 为后缀的文件,如果想要通过备份文件查看数据库版本,通常的做法就是把数据库还原,但是在还原的过程,如果不是相同的数据库版本,就会导致无法还原: 在数据库中,低 ...
- Magento2自定义命令
命令命名准则 命名指南概述 Magento 2引入了一个新的命令行界面(CLI),使组件开发人员能够插入模块提供的命令. Command name Command name 在命令中,它紧跟在命令的名 ...
- java实现sftp客户端上传文件夹的功能
使用的jar: <dependencies> <dependency> <groupId>jsch</groupId> <artifactId&g ...
- c++三种继承方式public,protect,private
C++中的三种继承public,protected,private 三种访问权限 public:可以被任意实体访问 protected:只允许子类及本类的成员函数访问 private:只允许本类的成员 ...
- 点评cat系列-服务器开发环境部署
我们有三种部署方式:1. docker 部署2. 采用官方的 war 包部署. 3. 源码部署 很显然 docker 部署是最简单的, 我尝试了多次, 都在 cat docker 容器镜像的编译过程失 ...
- Aurora — 一个在 MSOffice 内输入 LaTeX 公式的很好用插件
from http://blog.csdn.net/GarfieldEr007/article/details/51452986 工具名称:Aurora2x (下载) 压缩包内有详细的安装说明. 刚 ...