C语言关键字之volatile

版权声明:本文为小生原创,转载请注明出处,好吗好的,善哉善哉!!! https://blog.csdn.net/u010650845/article/details/79641385

1. Volatile关键字

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


1.1. Volatile详解

volatile 的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用 volatile 声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用 volatile 声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)

int flag = 0;
int main( void ){

    while( 1 ){
        if( flag )/* 等待flag 变为1*/
            do_something();
    }
}
void interrupt_isr( void ){
    flag = 1;
}

程序的本意是希望 interrupt_isr 中断产生时,在 main 当中调用 do_something 函数,但是由于编译器判断在main函数里面没有修改过 flag,因此可能只执行一次对从 flag 到某寄存器的写操作,然后每次 if 判断都只使用这个寄存器里面的“flag 副本”,导致 do_something 永远也不会被调用。如果变量加上 volatile 修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。这个例子中 flag 应该声明为 volatile int flag = 0;

需要注意的是,没有 volatile 也可能能正常运行,但是可能修改了编译器的优化级别之后就又不能正常运行了。因此经常会出现 debug 版本正常,但是 release 版本却不能正常的问题。所以为了安全起见,只要是等待别的程序修改某个变量的话,就加上 volatile 关键字。


1.2. Volatile用途

一般说来,volatile 用在如下的几个地方:
1. 中断服务程序中修改的供其它程序检测的变量需要加 volatile;
2. 多任务环境下各任务间共享的标志应该加 volatile;
3. 存储器映射的硬件寄存器通常也要加 volatile 说明,因为每次对它的读写都可能有不同意义;
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。

存储器映射的硬件寄存器情况举栗子:

假设要对一个设备进行初始化,此设备的某一个寄存器为 0xff800000

int *output = ( unsigned int* )0xff800000;
int init( void ){

    int i;
    for( i=0;i<10;i++ ){
        *output = i;
    }

}

经过编译器优化后,编译器认为前面循环半天都是废话,对最后的结果毫无影响,因为最终只是将 output 这个指针赋值为9,所以编译器最后给你编译的代码结果相当于:

int init( void ){
    *output = 9;
}

如果你对此外部设备进行初始化的过程是必须是像上面代码一样顺序的对其赋值,显然优化过程并不能达到目的。反之如果你不是对此端口反复写操作,而是反复读操作,其结果是一样的,编译器在优化后,也许你的代码对此地址的读操作只做了一次。然而从代码角度看是没有任何问题的。这时候就该使用 volatile 通知编译器这个变量是一个不稳定的,在遇到此变量时候不要优化。

volatile int *output=( volatile unsigned int* )0xff800000;

1.3. Volatile与Const

问题:一个参数是 const 还可以是 volatile 吗?
可以的,例如只读的状态寄存器。它是 volatile 因为它可能被意想不到地改变,同时也是 const 因为程序不应该试图去修改它。

猜你喜欢

转载自blog.csdn.net/u010650845/article/details/79641385