volatile

volatile:

    1.readme:修饰符[表示易变的],对于关键字修饰的变量,编译器对访问该变量的代码就不再进行优化[由于可能会被意想不到地改变,OS,多线程,硬件中断等],
    从而可以提供对特殊地址的稳定访问。 精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这

    2.编译器优化【为了提高效率】:
    int a = 2;
    int b = a;
    。......
    int c = a;
    当编译器发现b的数值未改变,直接c=b,而不在去取a的数值。或者[内存中有a的数值,编译器不再去读取寄存器,外存a的数值],看来优化也可能出现问题的。
    为了使运行更加快速,直接将线程变量[copy到register里,或者只读cache里的数值], 这样外部改变不是反应不了了。【如此优化会很terrible】!!

    3.volatile 必要性【例子】:
        1.多线程应用中被几个任务共享的变量(share variables);
        2.一个中断服务子程序中会访问到的非自动变量(Non-automatic variables);
        3.并行设备的硬件寄存器(status register);
        嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所以应当考虑何时需要用volatile类型的变量。

    4.糟糕的使用 volatile:
        这段代码可能有点恶作剧的味道。但它很好说明volatile类型参数的含义和作用。
        这段代码的目的是用来返指针*ptr所指向的值的平方,
        但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码【虽然看起来,一般状况下,运行结果都OK】:
        int square(volatile int *ptr)
        {
            int a,b;
            a = *ptr;
            b = *ptr;
            return a * b;
        }
        由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不
        是你所期望的平方值!正确的代码如下:
        long square(volatile int *ptr)
        {
            int a;
            a = *ptr;
            return a * a;
        }   

    5.volatile 经典问题:
        当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
        question 1. 一个参数既可以是const还可以是volatile吗?解释为什么。
        answer: 可以是。例如对于只读的状态寄存器而言,如果它仅仅是volatile类型,那么它还是可能被意想不到的改变。
                但它还是const的时候,程序就不应该试图去修改它

        question 2. 一个指针可以是volatile 吗?解释为什么。
        answer:可以是的。尽管这种情况并不常见,但它还是可以。一个例子就是:当一个中断服务子程序企图去修改一个指向一个buffer指针的时候。
                当然指针也需要存储【内存或者register】,就可能改变。
        question3:可能会被编译器不小心优化  
            1.for ( int i=0; i<100000; i++)   ; 

            2.void interrupt(void) {    i=1; } 
            int main(void) 
            { 
                while (1) 
                { 
                    if (i) dosomething(); 
                } 
            }               


    6.[不常见]直接修饰C函数返回值,方便编译器进行优化
        我们会在一些代码中用volatile关键字来修饰函数,如linux0.12的源代码中就有这样的语句:
        在linux的source code(linux/mm/memory.c)中有这样两句:
        volatile void do_exit(long code); 
        static inline volatile void oom(void) 
        { 
            printk("out of memory\n\r"); 
            do_exit(SIGSEGV); 
        }
        那么这里的volatile是什么意思呢?查了很多资料,都是说volatile对变量作用的结果,很少谈及对函数名修饰的作用。
        其实这里的作用是帮助编译器进行优化,而不是防止编译器优化,对应oom()和do_exit()函数而言,它们是永远都不会返回的,如果还将调用它们的函数的返回地址保存在堆栈上的话,是没有任何意义的,
        但是加了volatile过后,就意味着这个函数不会返回,就相当于告诉编译器,我调用后是不用保存调用我的函数的返回地址的。这样就达到了优化的作用。
        这种优化来源于GCC,在GCC2.5版本以后,使用noreturn属性来做优化,如void fatal () __attribute__ ((noreturn));,但是在Gcc2.5的版本以前,没有noreturn属性,所以就用volatile来表示不会返回的函数,以此达到优化的效果。


    7.修饰嵌入式汇编,防止编译器进行优化,以及volatile的作用是为了避免函数内部汇编指令的乱序执行。

    8.验证volatile的作用
        注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,
        测试有无volatile关键字,对程序最终代码的影响: 
        首先,用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的代码:  
        #include <stdio.h> 
        void main() 
        { 
            int i=10; 
            int a = i; 
            printf("i= %d",a); 
            //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
            __asm { 
            mov dword ptr [ebp-4], 20h 
            } 
            int b = i; 
            printf("i= %d",b); 
        }       
        然后,在调试版本模式运行程序,输出结果如下: 
        i = 10 
        i = 32 
        然后,在release版本模式运行程序,输出结果如下: 
        i = 10 
        i = 10 
        输出的结果明显表明,release模式下,编译器对代码进行了优化,第二次没有输出正确的i值。
        下面,我们把 i的声明加上volatile关键字,看看有什么变化: 
        #include <stdio.h> 
        void main() 
        { 
            volatile int i=10; 
            int a = i; 
            printf("i= %d",a); 
            __asm { 
            mov dword ptr [ebp-4], 20h 
            } 
            int b = i; 
            printf("i= %d",b); 
        }       
        分别在调试版本和release版本运行程序,输出都是: 
        i = 10 
        i = 32 
        这说明这个关键字发挥了它的作用! 

        参考资料:
        1.http://blog.21ic.com/user1/2949/archives/2007/35599.html
        2. http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
        3. http://www.kernelchina.org/node/618
        4.http://drdobbs.com/184401756
        5. http://bbs.emath.ac.cn/archiver/tid-3172.html
        6.http://www.cnblogs.com/justinzhang/archive/2011/09/28/2194657.html
        /-----------------------    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值