• 【转】volatile


     一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
    1) 并行设备的硬件寄存器(如:状态寄存器)
    2) 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
    3) 多线程应用中被几个任务共享的变量
    回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难。假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
    1)一个参数既可以是const还可以是volatile吗?解释为什么。
    2); 一个指针可以是volatile 吗?解释为什么。
    3); 下面的函数有什么错误:
    int square(volatile int *ptr)
    {
    return *ptr * *ptr;
    }
    下面是答案:
    1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
    2); 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修该一个指向一个buffer的指针时。
    3) 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
    int square(volatile int *ptr)
    {
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
    }
    由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
    long square(volatile int *ptr)
    {
    int a;
    a = *ptr;
    return a * a;
    }

    转自:http://blog.csdn.net/haozhi_hit/article/details/1393615#comments

    volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如

    操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行

    优化,从而可以提供对特殊地址的稳定访问。

    使用该关键字的例子如下:

    int volatile nVint;

    当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指

    令刚刚从该处读取过数据。而且读取的数据立刻被保存。

    例如:

    volatile int i=10;
    int a = i;
    。。。//其他代码,并未明确告诉编译器,对i进行过操作
    int b = i;

    volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的

    汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间

    的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果

    i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问

    注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编

    代码,测试有无volatile关键字,对程序最终代码的影响:

    首先用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的代码:

    #include <stdio.h>
    void main()
    {
     int i=10;
     int a = i;

     printf("i= %d\n",a);
            //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
     __asm {
      mov         dword ptr [ebp-4], 20h
     }

     int b = i;
     printf("i= %d\n",b);
    }

    然后,在调试版本模式运行程序,输出结果如下:
    i = 10
    i = 32

    然后,在release版本模式运行程序,输出结果如下:
    i = 10
    i = 10

    输出的结果明显表明,release模式下,编译器对代码进行了优化,第二次没有输出正确的i值。

    下面,我们把 i的声明加上volatile关键字,看看有什么变化:


    #include <stdio.h>
    void main()
    {
     volatile int i=10;
     int a = i;

     printf("i= %d\n",a);
     __asm {
      mov         dword ptr [ebp-4], 20h
     }

     int b = i;
     printf("i= %d\n",b);
    }

    分别在调试版本和release版本运行程序,输出都是:
    i = 10
    i = 32

    这说明这个关键字发挥了它的作用!

    转自:http://blog.vckbase.com/iwaswzq/archive/2004/12/05/1896.aspx

  • 相关阅读:
    Java基础--JDBC
    DQL---连接查询(内连接、外连接)、子查询、分页查询
    Java基础--注解、反射
    1、Centos7系统安装docker,并配置阿里云镜像加速器
    linux——vim命令
    linux——yum命令
    linux——ps命令
    31、springboot——缓存之JSR107——@Caching和@CacheConfig的使用⑤
    30、springboot——缓存之JSR107——@CacheEvict的使用④
    30、springboot——缓存之JSR107——@CachePut的使用③
  • 原文地址:https://www.cnblogs.com/dahai/p/2098363.html
Copyright © 2020-2023  润新知