一、volatile关键字原理 提醒编译器,该关键字后面的变量随时会发生改变,在编译后的程序中,存储或读取该变量时,编译器不会对它进行优化处理,会直接从变量内存地址中直接处理数据。从而可以对特殊地址的稳定访问。 二、volatile用法 简单地说就是防止编译器对代码进行优化。比如如下程序: Dat[2]=0x55; Dat[2]=0x56;
对外部硬件而言,上述2条语句分别表示不同的操作,会产生2种不同的动作,但是编译器却会对上述2条语句进行优化,认为只有Dat[2]=0x56(即忽略前1条语句,只产生1条机器代码)。如果键入volatile,则编译器会逐一地进行编译并产生相应的机器代码(产生2条代码)。 再举一个例子: int a = 10; int b = a; int c = a;
编译器在执行这段代码时会发现a变量未做相关操作,它会自动把上次读取a的值直接赋值给c,这时如果a是寄存器变量或者端口数据时,就会容易出问题,这时需要添加volatile变量如下: volatile int a = 10; int b = a; int c = a;
这时,每次读取a变量的值都是直接从内存地址中获取。
一般在什么情况出现: 1)并行设备的硬件寄存器 2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3)多线程应用中被几个任务共享的变量 一般说来,volatile用在如下的几个地方:
1) 中断服务程序中修改的供其它程序检测的变量,需要加volatile; 当变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中读取变量副本,使得中断程序的操作被短路。
2) 多任务环境下各任务间共享的标志,应该加volatile; 在本次线程内, 当读取一个变量时,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当内存变量或寄存器变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致 。
3) 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义; 假设要对一个设备进行初始化,此设备的某一个寄存器为0xff800000。for(i=0;i< 10;i++) *output = i;前面循环半天都是废话,对最后的结果毫无影响,因为最终只是将output这个指针赋值为9,省略了对该硬件IO端口反复读的操作。
|