volatile

来源:互联网 发布:压缩密码破解软件 编辑:程序博客网 时间:2024/05/16 03:58

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