简说volatile关键字

volatile

volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,编译器对访问该变量的代码就不再进行优化,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。

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

举几个例子


1、(禁止优化作用

unsigned int *ip = 0x12345678;
*ip = 1;
*ip = 2;

这个程序则会被系统优化为:

unsigned int *ip = 0x12345678;
*ip = 2;

这可能在信号传递或者时序的操作的时候会发生错误
如果ip定义为volatile则不会进行任何优化。


2、(用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能重复使用放在cache或寄存器中的备份
实际上这也是优化的一种,每次读取数据进内存进行读取(速度减慢)。这就是volatile不能过度使用的原因。
例如以下中断程序:

int i=0; 
int main(void) {
     ...
     while (1){   
          if (i) dosomething();     
     }/* Interrupt service routine. */
void ISR_2(void){      
    i=1;
}

所以总结volatile经常应用的场景为:

  1. 中断服务程序中修改的供其它程序检测的变量需要加volatile(原因2)
  2. 多任务环境下(如多线程)各任务间共享的标志应该加volatile(原因2)
  3. 存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义(原因1)

例如:假设要对一个设备进行初始化,此设备的某一个寄存器为0x12345678,发送一个锯齿波。

int  *output = (unsigned  int *)0x12345678;//定义一个IO端口;
int init(void){
    int i;      
    for(i=0;i< 10;i++){     
        *output = i;
    }
}

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

int  *output = (unsigned  int *)0x12345678;//定义一个IO端口;
int  init(void){
    *output = 9;
}

所以解决方法为加上一个volatile关键字,禁止程序进行优化。

volatile  int *output=(volatile unsigned int *)0x12345678;//定义一个I/O端口

总结:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错

常见问题

一个参数既可以是const还可以是volatile吗?

可以的,例如只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

一个指针可以是volatile 吗?

可以,可以把指针看成一个变量,和变量的实质是一样的。

例子

int square(volatile int *ptr){
    return *ptr * *ptr;
}

这个函数要完成的是返回ptr指向的变量的平方,可以看出volatile属实多此一举,这是由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int *ptr){
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
}

在运行过程中由于是volatile变量,ptr会意想不到的改变,因此a和b可能是不同的。所以如果一定要输入volatile变量的话可以这么做:

long square(volatile int *ptr){
    int a;
    a = *ptr;
    return a * a;
}

可以看出使用volatile还会增加代码的长度,所以不能滥用volatile。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值