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,如需转载请自行联系原作者


相关文章
|
4月前
|
存储 程序员 C语言
C语言关键字是什么?什么是关键字?什么是字符和ascll码值
C语言关键字是什么?什么是关键字?什么是字符和ascll码值
|
6月前
|
存储 编译器 C语言
C语言——关键字详解
C语言——关键字详解
|
6月前
|
C语言
带你熟知关键字static用法——C语言(举例及通俗易懂)
带你熟知关键字static用法——C语言(举例及通俗易懂)
50 0
|
7月前
|
存储 Java C#
C语言入门(1)——特点及关键字
面向过程 一般用于嵌入式开发、编写最底层的程序、操作系统
80 0
|
29天前
|
程序员 C语言
在C语言中,typedef是一种用来创建新的数据类型名的关键字
在C语言中,typedef是一种用来创建新的数据类型名的关键字
9 0
|
29天前
|
存储 编译器 C语言
C语言的关键字
C语言的关键字
13 0
|
1月前
|
存储 编译器 C语言
c语言中的关键字
c语言中的关键字
8 0
|
5月前
|
存储 安全 编译器
13 C++ - const关键字(比较C语言)
13 C++ - const关键字(比较C语言)
42 0
|
1月前
|
编译器 程序员 Linux
深入理解C语言中的return关键字与函数返回机制
深入理解C语言中的return关键字与函数返回机制
|
1月前
|
C语言
C语言中关键字static的三种用法
C语言中关键字static的三种用法