打印

哪些变量应该加volatile?

[复制链接]
7117|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
komad|  楼主 | 2010-11-12 20:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
大家用C编程时,哪些变量应该加volatile,网上有说在中断里的变量要加上volatile关键字?如果这个变量在主程序里经常用到而经常被改变,在中断程序里经常被改变,那这个变量应该加上volatile吗?还是说这个变量在主程序里可能不会被改变,而在中断经常被改变,这个volatile是不是一定要加上?:dizzy: 可以一起讨论下。

相关帖子

沙发
komad|  楼主 | 2010-11-12 20:13 | 只看该作者
volatile指的是易变的,编译器在优化时,可能不会读变量的初始地址,而读过来的是前一次的,那这种情况在什么时候会发生?那些不用加volatile关键字的变量,为什么每次读的是初始地址?不知道我说变量的初始地址对不对?

使用特权

评论回复
板凳
zdhlixiang2006| | 2010-11-12 20:39 | 只看该作者
只知道这样写,编译器会优化代码,别的不清楚,等待高手解答

使用特权

评论回复
地板
liang7143| | 2010-11-12 22:49 | 只看该作者
在中断中改变的变量~~一般建议加上。

使用特权

评论回复
5
原野之狼| | 2010-11-13 00:42 | 只看该作者
本帖最后由 原野之狼 于 2010-11-13 00:56 编辑

举个例子:
假如你向一个寄存器进行写操作,先写0xAA,接着再写0x55。这种操作可能是很有必要的。
但是编译器在进行优化的时候有可能认为这是个冗余,只用一句来表示。显然这是我们不希望看到的。

再举个例子:
后台程序中有这样的语句
while(!flag);
而前台程序(ISR)中会对flag进行改写,如过在后台程序中的判断操作不是从flag的真实地址处取数据,那么在ISR中的修改将不起作用。开启优化后,后台程序中flag会缓冲到寄存器,然后不断地while(寄存器);
寄存器的内容跟ISR里修改的flag并无关联。

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
komad + 1
6
komad|  楼主 | 2010-11-13 13:36 | 只看该作者
那这个volatile关键字是在编程的时候加呢?还是在调时加?
比如:变量在中断,按常理这个变量就要加上volatile关键字,但如果中断不影响这个变量,又或者说这个变量是一般正常情况下的变量,或者说这个变量要不要优化我不清楚?那这种情况只能调试程序时去发现了?
或许我这个问题就是多余的。。。;P

使用特权

评论回复
7
ayb_ice| | 2010-11-13 15:19 | 只看该作者
不想被优化的变量就应该加
比如SFR,其实很多编译器将SFR当普通RAM对待

使用特权

评论回复
8
智多芯| | 2010-11-13 15:49 | 只看该作者
变量不加volatile的话,默认是优化的,如下:
int a = 100;
int b = a;
int c = a;
在执行程中,如果第二条语句和第三条语句之间变量a未成用作左值,那么即使变量被某些操作(如中断)改变成200了,执行完后变量c还是等于100。
如果加了volatile的话,在执行int c = a;语句的时候,会重新从内存取出a的值(此时为200),所以c会等于200。

使用特权

评论回复
9
dong_abc| | 2010-11-13 17:23 | 只看该作者
嵌入式编程中经常用到 volatile这个关键字,在网上查了下他的用法可以归结为以下两点:

一:告诉compiler不能做任何优化    比如要往某一地址送两指令:   
   int   *ip   =...;   //设备地址   
   *ip   =   1;   //第一个指令   
   *ip   =   2;   //第二个指令   
   以上程序compiler可能做优化而成:   
   int   *ip   =   ...;   
   *ip   =   2;   
   结果第一个指令丢失。如果用volatile, compiler就不允许做任何的优化,从而保证程序的原意:   
   volatile   int   *ip   =   ...;   
   *ip   =   1;   
   *ip   =   2;   
   即使你要compiler做优化,它也不会把两次付值语句间化为一。它只能做其它的优化。这对device   driver程序员很有用。
二:表示用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能把他放在cache或寄存器中重复使用。    如  volatile   char   a;   
       a=0;   
       while(!a){   
          //do   some   things;   
      }   
      doother();   
   如果没有   volatile   doother()不会被执行  

本文引用通告地址:http://lionwq.spaces.**/articles/article/item/16724#

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
komad + 1
10
komad|  楼主 | 2010-11-13 18:28 | 只看该作者
其实还是叫compiler老实点,不要优化,呵呵

使用特权

评论回复
11
shizaigaole| | 2010-11-13 20:47 | 只看该作者
本帖最后由 shizaigaole 于 2010-11-13 20:49 编辑

三种情况要加volatile

1.RAM映射的外设寄存器定义
2.中断和大循环都会用到的公共全局变量
3.实时操作系统中,用作不同任务之间同步的公共变量。

这些变量随时会被外部硬件信号,中断例程,高优先级任务改变,
即所谓易变的的变量,
当然不能用通用寄存器替换优化或者合并优化,
否则会出问题。

所以要用volatile关键字告诉编译器,
这个变量是易变的,
不要进行优化。

使用特权

评论回复
评分
参与人数 2威望 +2 收起 理由
komad + 1
dong_abc + 1
12
komad|  楼主 | 2010-11-14 17:07 | 只看该作者
shizaigaole

当然不能用通用寄存器替换优化或者合并优化,
否则会出问题。


什么意思?没能理解

通用寄存器怎么替换优化?合并优化?
请教shizaigaole:handshake

使用特权

评论回复
13
shizaigaole| | 2010-11-14 20:23 | 只看该作者
本帖最后由 shizaigaole 于 2010-11-14 20:26 编辑

更正一下,应该叫通用寄存器替换合并优化比较好一点。

例如:

B = A +1;
........
C = A + 10;
........
D = A + 100;

如果在这段代码中,A没有改变,
对于大多数通用寄存器比较多的MCU来说,
可能会先把A传到一个通用寄存器中,
后面的操作A都用这个通用寄存器代替,
因为对大多数MCU来说寻址通用寄存器的指令比寻址RAM指令周期要短,
这样的话可以达到加快程序执行速度的目的。


但是对于“易变的变量”,随时可能被后台代码改变,
这样的优化反而会导致错误,
所以要用volatile关键字告诉编译器,
这个变量是易变的,
不要进行优化。

使用特权

评论回复
14
komad|  楼主 | 2010-11-15 14:01 | 只看该作者
shizaigaole

:victory:
如果A有机会被改变,而没加volatile,被优化了,可能就会出错

使用特权

评论回复
15
xlsbz| | 2010-11-15 16:28 | 只看该作者
建议楼主的题目改成  哪些情况下 不应该加 olita饿啊啊

使用特权

评论回复
16
komad|  楼主 | 2010-11-15 21:08 | 只看该作者
建议楼主的题目改成  哪些情况下 不应该加 olita饿啊啊
xlsbz 发表于 2010-11-15 16:28

ksk ksk :victory: :handshake

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

118

帖子

0

粉丝