当前位置:   article > 正文

Volatile解释_volatile *square**square

volatile *square**square

编译器

编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些多余的代码减少占用空间。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化。

volatile解释

  • volatile的本意是“易变的”意思,表示定义的这个变量是容易变化的。 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。
  • 当使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行加速优化每次总是从内存读-执行动作-写内存,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)
//假如定义一个IO地址,IO地址确实需要从0到10依次赋值,写了下面循环。
int  *output = (unsigned  int *)0xff800000;//定义一个IO端口地址;
int init(void)
{
      int i;
      for(i=0;i< 10;i++){
         *output = i;
}
//上述没定义volatile,编译器会认为你在做些费事,所以最后代码优化等效于
int init(void)
{
      int i;
      *output = 9;
}
/*
假如外部设备进行初始化的过程是必须是像上面代码一样顺序的对其赋值,显然优化过程并不能达到目的。反之如果你不是对此端口反复写操作,而是反复读操作,其结果是一样的,编译器在优化后,也许你的代码对此地址的读操作只做了一次。然而从代码角度看是没有任何问题的。这时候就该使用volatile通知编译器这个变量是一个不稳定的,在遇到此变量时候不要优化。
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
//这个函数返回一个数值平方是错误的
int square(volatile int *ptr)
{
    return (*ptr) * (*ptr);
}
//编译器优化后产生下面代码,由于*ptr的值可能被意想不到地改变,因此计算过程中a,b的数值可能会改变。
int square(volatile int *ptr)
{
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
}
//正确代码应该修改为这个
long square(volatile int *ptr)
{
    int a;
    a = *ptr;
    return a * a;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
int a = 1;
int *ip =&a //设备地址 
*ip = 1; //第一个指令 
*ip = 2; //第二个指令 
//以上程序compiler可能做优化直接将第一个赋值丢了,认为是无效的 
int *ip = &a; 
*ip = 2; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

volatile常用地方

  • 中断服务程序中修改的供其它程序检测的变量需要加volatile,确保每次都直接读取操作。这个真的很重要,刚刚又被这个弄错了一次,因为没有加,导致在while里面判断的时候时钟不成功,但是调试的时候,数值确实改变了,因为编译器通过优化,使得每次变量都从寄存器里面读取出来,而不是从内存中读取出来。
  • 多任务环境下各任务间共享的标志应该加volatile。
  • 存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。
    unsigned char temp = 0x11;
    AT24CXX_WriteOneByte(100,0xaa);
    temp = AT24CXX_ReadOneByte(100);
  • 1
  • 2
  • 3

main.c(39): warning: #550-D: variable “temp” was set but never used,有了一个提示,那么这个变量肯定是被优化了。因为没有把一个变量当作右值使用,所以优化了。需要定义成 volatile unsigned char temp = 0x11;才可以,证明这个确实需要这样赋值,编译器你千万不要优化。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号