首先看一下单词“volatile”的释义:

volatile [ˈvɑlətl]

adj.  易变的,不稳定的; (液体或油)易挥发的; 爆炸性的; 快活的,轻快的;

下边是“C++ Primer”对volatile讲解的部分摘录:

“当一个对象的值可能会在编译器的控制或监测之外被改变时,该对象应该声明为volatile。因此,编译器执行的某些例行优化行为不能应用在已经指定为volatile的对象上……volatile修饰符的主要目的是提示编译器,该对象的值可能在编译器未监测到的情况下被改变。因此编译器不能武断地对引用这些对象的代码作优化处理。”

可见,修饰符volatile定义了一个“易变的、不稳定的、随时可能改变的”变量,对于被声明为volatile的变量的使用上跟普通的变量没有什么区别,最大的影响,就是编译器不能按照常规方式对其进行优化。

这就引入了两个问题:

编译器为何对访问变量的方式做优化以及如何优化?

编译器为何优化:

首先有这么个前提明确一下:编译器对变量的存取速度,寄存器快于内存,最慢是硬盘。

寄存器快于内存的主要原因体现在两者工作方式的差别上:

寄存器本身位于CPU内部,使用起来非常简单:第一,找到相关的位,第二,读取这些位,Over。

相比之下,内存的工作方式就复杂很多:

1.找到数据的指针(指针可能存放在寄存器内,所以这一步就已经包括寄存器的全部工作了。)

2.将指针送往内存管理单元(MMU),由MMU将虚拟的内存地址翻译成实际的物理地址。

3.将物理地址送往内存控制器(memory
controller),由内存控制器找出该地址在哪一根内存插槽(bank)上。

4.确定数据在哪一个内存块(chunk)上,从该块读取数据。

5.数据先送回内存控制器,再送回CPU,然后开始使用。

相对复杂的工作流程产生了更多的时延,累计起来就比寄存器慢很多,为了提高执行效率,编译器会对有必要优化的变量做访问方式上的处理,这就是编译器对变量的优化。

如何优化:

多数情况下,变量是存放在内存而非寄存器中的,这样对变量的存取效率很低。对于频繁使用的变量,编译器自动地把变量mov到寄存器里,使用的时候直接访问寄存器里的值,以加快存取速度,这就是寄存器对变量的优化。

早期C编译程序时不会把变量保存在寄存器中,除非显示使用关键字register修饰变量:

  1. register long int value=123456789;

该关键字提醒编译器,所定义的变量会在程序中频繁被使用,建议编译器将其保存在CPU的寄存器中,以加快存取速度。其后随着编译技术的进步,编译器比程序员能更好的决定变量是应该存储在内存还是寄存器中,早在C++ 98/03标准中就明确,用register关键字声明的变量和不使用该关键字声明的变量一样,都具有自动存储期,现在在标准C++中,虽然还可以使用该关键字,但已经不再影响变量的实际定义。

对于被volatile 关键字修饰的变量,已经提前告知编译器该变量可能被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问,也就是说系统总是从它所在的内存地址读取数据,而非寄存器,并且使用完成之后立即按原路保存该变量的更改到内存。

volatile用法

volatile的用法跟关键字const用法一样
  1. <pre name="code" class="cpp">volatile long clock_register;
  1.  

被volatile修饰的变量表示该变量会在意想不到的情况下改变,而const修饰的变量表示变量是不可改变的,那么一个变量能否同时使用volatile和const修饰呢?

  1. volatile const long clock_register;
  1. const volatile long clock-register;

答案是肯定的,一个例子是只读的状态寄存器,用volatile修饰表示它可能会被意想不到的情况改变,这里是指编译器外部的情况,用const修饰表示在程序内部,不应该试图去人为修改它的值。


C++中volatile及编译器优化的更多相关文章

  1. Visual C++中的编译器优化

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:Visual C++中的编译器优化.

  2. 【转】C 编译器优化过程中的 Bug

    C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...

  3. Xcode4.4(LLVM4.0编译器)中NSArray, NSDictionary, NSNumber优化写法

    Xcode4.4(LLVM4.0编译器)中NSArray, NSDictionary, NSNumber优化写法 从xcode4.4开始,LLVM4.0编译器为Objective-C添加一些新的特性. ...

  4. C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理

    C#编译器优化那点事   使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...

  5. C++ 中 volatile 的使用

    一.作用 volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值. 简单地说就是防止编译器对代码进行优化.比如如下程序:XBYTE[2]=0x55;XBY ...

  6. Java中Volatile关键字详解

    一.基本概念 先补充一下概念:Java并发中的可见性与原子性 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值, ...

  7. 详解C中volatile关键字

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储 ...

  8. java多线程中 volatile与synchronized的区别-阿里面试

    volatile 与 synchronized 的比较(阿里面试官问的问题) ①volatile轻量级,只能修饰变量.synchronized重量级,还可修饰方法 ②volatile只能保证数据的可见 ...

  9. Java中volatile关键字解析

    一.内存模型的相关概念 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存 ...

随机推荐

  1. html--添加、删除滚动条

    1:若想给div添加滚动条: style="overflow-y:scroll";(添加纵向滚动条) style="overflow-x:scroll";(添加 ...

  2. 带你学Node系列之express-CRUD

    前言 hello,小伙伴们,我是你们的pubdreamcc,本篇博文出至于我的GitHub仓库node学习教程资料,欢迎小伙伴们点赞和star,你们的点赞是我持续更新的动力. GitHub仓库地址:n ...

  3. 【深入Java虚拟机】之五:多态性实现机制——静态分派与动态分派

    方法解析 Class文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址.这个特性给Java带来了更强大的动态扩 ...

  4. JS---数组(Array)处理函数整理

    1.concat() 连接两个或更多的数组该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本.例如: 代码如下: <script type="text/javascript&q ...

  5. win7配置java环境变量

    http://jingyan.baidu.com/article/9f63fb91d87fb0c8400f0e93.html 安装JDK,从Oracel官方网站上下载,也可以通过搜索,进入链接.下载完 ...

  6. flask的run的运行参数含义

    直接阅读源代码吧: 在flask的app.py里,查看run函数的定义 def run(self, host=None, port=None, debug=None, **options): &quo ...

  7. Swift标识符和keyword

    不论什么一种计算机语言都离不开标识符和keyword,下面我们将具体介绍Swift标识符和keyword. 标示符 标识符就是给变量.常量.方法.函数.枚举.结构体.类.协议等指定的名字.构成标识符的 ...

  8. Android——坐标系及转化

    一.坐标系 Android应用层坐标系原点在左上角,坐标范围(0,0)——(width,height). Android底层坐标系原点在屏幕中央,坐标范围(-1000,,1000)——(1000,10 ...

  9. 新生入学V3.0颗粒归仓

    新生入学系统V3.0接近尾声.每次做项目都有不一样的收获.V1.0,V2.0主要是熟悉了整个项目流程是怎样进行的,可行性分析--需求分析(原型图Axure)--实体设计(PD)--类图时序图(EA)- ...

  10. 从头学起-CLR的执行模型

    1.将源代码编译成托管代码 公共运行时(Common Language Runtime) a.面向运行时的所有语言都可以通过异常报告错误 b.面向运行时的所有语言都可以创建线程 c.核心功能:管理内存 ...