进入厂区安全注意事项:volatile分析

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 00:29:34
作用:(1)阻止编译器为了提高速度将一个变量缓存到寄存器中而不写回(就是说在用到这个变量时必须每次都从内存重新读取这个变量的值,而不是使用保存在寄存器里的备份)。(2)阻止编译器调整操作volitile变量的指令顺序。。用它声明的类型变量估计会被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。下面是volatile变量的几个例子:     1). 并行设备的硬件寄存器(如:状态寄存器)
    2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
    3). 多线程应用中被几个任务共享的变量
    
    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;
     } 
一般说来,volatile用在如下的几个地方: 

1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 

2、多任务环境下各任务间共享的标志应该加volatile; 

3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义; 


另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实 
现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。 
------------简明示例如下:------------------


注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无volatile关键字,对程序最终代码的影响:
>>>>首先,用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的代码:
>>
#i nclude 
void main() {  int i=10;  int a = i;  printf("i= %d",a);  //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道  __asm {  mov dword ptr [ebp-4], 10h  }  int b = i;  printf("i= %d",b); }     
然后,在调试版本模式运行程序,输出结果如下:
i = 10
i = 32
然后,在release版本模式运行程序,输出结果如下:
i = 10
i = 10
输出的结果明显表明,release模式下,编译器对代码进行了优化,第二次没有输出正确的i值。下面,我们把 i的声明加上volatile关键字,看看有什么变化:
#i nclude 
void main() {  volatile int i=10;  int a = i;  printf("i= %d",a);  //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道  __asm {  mov dword ptr [ebp-4], 10h  }  int b = i;  printf("i= %d",b); }     
分别在调试版本和release版本运行程序,输出都是:
i = 10
i = 32
这说明这个关键字发挥了它的作用!


典型的例子
for ( int i=0; i<100000; i++);
这个语句用来测试空循环的速度的
但是编译器肯定要把它优化掉,根本就不执行
如果你写成 
for ( volatile int i=0; i<100000; i++);
它就会执行了

volatile的本意是“易变的” 
由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如: 中断处理程序中

static int i=0;

int main(void)
{
...
while (1)
{
if (i) dosomething();
}
}

/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}