C语言关键字volatile

简介:
C语言关键字volatile 
(总结网友经验给初学者) 
关键字volatile是什么声明? 
        将一个变量说明为volatile表示这个变量是“易变的”。如果一个变量会被其它引用改变,或在其它并行的 
任务中会被改变(例如中断服务程序),都要显式地说明为“volatile”,否则在编译器优化阶段会作出错误的判 
断,例如将这个变量读入寄存器以后,在没有对这个变量赋值以前,会一直使用寄存器中的值,而实际上这个变 
量的值可能已经被一个指针引用改变了,或者是在中断服务程序中被改变了,下面这个例子说明这种错误: 
        有一个变量T,在定时中断中每隔一个固定时间减一,然后在主程序中等待它减到0 
unsigned  char  T; 
void  T0_int(void)  interrupt 

    ... 
    T--; 
    ... 

void  main(void) 

    ... 
    T=10; 
    while  (T!=0);       
    ... 

正确的写法应该是将第一句改为: 
volatile  unsigned  char  T; 
*注:这个例子并不是针对特定的编译器,所以可能在有些编译器中能正确编译。但作为一个健壮的程序,一定要 
注意这一点,否则即使能得到正确结果,也会给程序移植或升级带来意想不到的问题。 



ARM编程:从“有关硬件寄存器、volatile、和不该发生的C编译器优化”谈volatile修饰的变量 
说到的问题的确是经常发生:  特别是在大系统中  类似的问题包括TC  BC等都出现过 
但是  反而是Keil较少出现-_-! 
其实  这个问题归根到底  就是volatile和变量优化的问题 
简单的说  C编译器  为了“偷懒”-_-b  在他认为你这个变量不会被修改的时候  就把相应的 
代码给“喀嚓”掉 
比如龙大的那个程序: 
void  IRQHandler(void) 

        u16  Int_Flag; 
        Int_Flag  REG_IF;                //  Read  the  interrupt  flags 
        SV32Bit++; 
        REG_SCCNT=0x5080; 
        REG_IF  Int_Flag;                //  Write  back  the  interrupt  flags 

编译器看Int_Flag  好像是个没有在函数内被修改的变量  就偷懒  认为这个变量是无用的 
类似与我们在keil中写个 
char  xxx; 
main 

        char  a; 
        xxx 
        xxx 
        while(1);     

他多半是会把这样的代码给优化掉——  也就是不编译出代码了 
这个时候  volatile  就有用了  简单的说  所有的标准  编译器  遇见volatile修饰的变量 
都认为这个变量的值是随机的  任何时候都是不同的  这样  每次对这样的变量的读出和写入 
都必须实际的去读写对应的地址  而不可以偷懒用:寄存器中的拷贝中的数据、可能数值一 
样的其他变量/常数等来“糊弄”系统  ^_^ 
比如我上面的那个main()编译器发现  xxx被读出然后无修改的重新写入  就懒得麻烦读写  索 
性优化掉了 
其实  volatile  在大多数的代码中  很少使用 
简单的说:他用来修饰那些可能会在你不知道的地方给修改的变量  比如 
 
1.定义成寄存器空间的变量   事实上  这个是他最大的一个用处!! 
比如ARM/C51/AVR/PIC等等的控制寄存器(SFR)空间  虽然  Keil用了一个sfr关键字来修饰寄 
存器:sfr  P0      0x80  …… 
但是  在标准C中  是必须使用这样的形式:#define  P0  *(volatile  unsighed  char  *)0x80 
 
2.会被中断修改的变量 有时候也需要加 不过这个不是项上一个那样是绝对的 
和编译器本身和你选择的优化等级等有关系 我的建议 在ADS中最好还是加上 Keil中就可以 
不用麻烦了  
 
回到龙大的那个问题上  龙大的问题虽然解决了  不过并不好  因为他把 
u16  定义成了  volatile  unsigned  short  这个对程序运行结果不会造成任何影响  不过带来 
了一个无法对变量优化的毛病 
事实上  这个问题的带来  是因龙大使用的那个  gba.h的一个bug 
我看到网上很多的gba.h的寄存器的定义  都吧寄存器们定义成: 
#define  REG_XXX  *(u16*)0x??????的形式 
这样  当龙大的IRQHandler程序进入后  编译器认为: 
REG_IF没有在函数里给修改  也没有给真正赋值     
a=x; 
x=a; 
这样  IRQHandler函数  在形式上  也就被认为和后面我写的那个main一样了 
这样的代码  编译器肯定是喀嚓的了 
那么  如果只把gba.h中的REG_IF的定义  加上volatile  修饰  而u16  依然是  unsighed  short 
呢? 

当然是一切都解决了……


本文转自feisky博客园博客,原文链接:http://www.cnblogs.com/feisky/archive/2009/01/08/1586362.html,如需转载请自行联系原作者


相关文章
|
7月前
|
缓存 NoSQL 编译器
C语言的本质(四):volatile限定符
C语言的本质(四):volatile限定符
47 0
|
10天前
|
缓存 安全 编译器
【C语言】volatile 关键字详解
`volatile` 关键字在 C 语言中用于防止编译器对某些变量进行优化,确保每次访问该变量时都直接从内存中读取最新的值。它主要用于处理硬件寄存器和多线程中的共享变量。然而,`volatile` 不保证操作的原子性和顺序,因此在多线程环境中,仍然需要适当的同步机制来确保线程安全。
41 2
|
5月前
|
C语言
|
5月前
|
存储 C语言
C语言中static关键字的作用与用法解析
C语言中static关键字的作用与用法解析
|
6月前
|
存储 C语言
C语言中的typedef关键字:为类型定义新名称
C语言中的typedef关键字:为类型定义新名称
|
6月前
|
C语言
深入探索C语言中的sizeof关键字
深入探索C语言中的sizeof关键字
|
6月前
|
存储 编译器 C语言
C语言中的关键字与标识符详解
C语言中的关键字与标识符详解
140 0
|
7月前
|
算法 编译器 API
C语言易混淆、简单算法、结构体题目练习、常见关键字总结-1
C语言易混淆、简单算法、结构体题目练习、常见关键字总结
|
7月前
|
安全 编译器 C语言
C语言中的const关键字
C语言中的const关键字
61 2
|
7月前
|
存储 C语言
【C语言】数据:数据类型关键字
【C语言】数据:数据类型关键字