volatile:作为指令关键字,确保本条指令不会被编译器优化而被省略,要求每次都读值,例:
1 2 3 4 | XBYTE[2]=0x55; XBYTE[2]=0x56; XBYTE[2]=0x57; XBYTE[2]=0x58; |
编译器会优化,只操作最后的XBYTE[2]=0x58;但是对外部硬件来说这是4个操作,被优化了就会导致硬
件流程出现问题,只产生了一个机器码,因此需要加volatile修饰符。
一个变量被定义为volatile意思是这个变量可能会被意想不到的改变,读值保证了可以响应修改,不会
出现修改了但是读的还是之前的值的情况。修饰后编译器不能假设这个变量的值,只能每次都读取这个变量的
值,而不是寄存器中存着的。必须使用volatile的场合:
1.并行设备的硬件寄存器,比如状态寄存器
2.一个中断服务子程序可能访问的非自动变量
3.多线程应用中被几个程序共享的变量
注意的点:
1.一个参数可以既是const又是volatile,volatile保证被意外修改仍能读取到最新的值,const保证
不应该被修改
2.指针可以是volatile,例如中断服务子程序修改一个指向buffer的指针
编译器优化:在一个线程内,读取一个变量时,为了提高读取速度,编译器会把变量值放到内存中,以后
再读取时,直接从内存中读取。本线程内若改变变量值,会把新的值copy到寄存器,保持一致。别的线程改了
这个变量的值,寄存器值不变就会出问题。别的线程改了寄存器的值,变量值没变,就会出问题。
在debug版本,不会优化,在release版本,会被优化,所以release版本需要额外注意,内嵌汇编方法
#include<stdio.h>
void main(int argc,char *argv[])
{
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);
}
这个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | static int i = 0; int main(void) { //... while(1) { if(i) dosomething(); } } /*Interruptserviceroutine.*/ void ISR_2(void) { i=1; } |
本意是希望中断后i = 1,main函数响应,但是编译器判断main中没有修改i的值,因此可能只执行一次
从i到寄存器的读操作,然后每次判断都从寄存器中取副本,导致中断永远不会被响应,此时需要加volatile
中断服务程序中修改的供其他程序检测的变量需要加volatile