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
- volatile
- volatile
- Volatile
- volatile
- volatile
- volatile
- volatile
- volatile
- volatile
- Volatile
- volatile
- volatile
- volatile
- volatile
- volatile
- volatile
- volatile
- volatile
- 用XE7新开发的一个Android员工积分查询的案例
- 轻量级网络请求框架MKnetworkKit 介绍使用
- 排序算法之冒泡排序
- Linux中find常见用法示例
- 《Apache MINA 2.0 用户指南》第十一章:SSL 过滤器
- volatile
- 【控件篇】Popuwindow 新手使用误区讲解
- R文件丢失以及包不存在的解决方法
- 【ADB命令第三篇】手机密码(访问权限密码或者锁屏密码等)忘记怎么办?
- lightoj 1326 - Race dp+预处理
- BestCoder Round #34
- GitHub上的一些开源项目
- Unity3d skele插件 创建简单动画
- jquery中如何对添加的标签进行操作