zoukankan      html  css  js  c++  java
  • 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 
    呢? 
    当然是一切都解决了……
  • 相关阅读:
    deepin/uos和局域网其他机器无法ping通
    Ubuntu18.04完全卸载vscode
    批量拉取github组织或者用户的仓库
    vmware uos挂载windows共享目录
    清空容器另类方式
    time_t 时间格式化字符串
    条件变量condition_variable
    C++多维堆数组定义
    arm64 ubuntu18.04 bionic安装bcc tools
    win10下载编译chromium
  • 原文地址:https://www.cnblogs.com/feisky/p/1586362.html
Copyright © 2011-2022 走看看