探究在嵌入式中什么时候需要加volatile关键字
volatile关键字翻译:可变的、易变的
从字面意思来说,被volatile修饰过的变量,在任意时刻可能会被程序某处修改。
再加上编译器有这么一种机制:为了提高访问效率,程序会在进入某个函数时将这个函数需要用到的变量从ram拷贝到如R0这种的寄存器上。然后程序在访问这个变量的时候,会将R0寄存器当成这个变量来操作,在退出函数时再将R0寄存器里的最终操作后的值写回ram。这个比从ram里面每次操作取值快很多。
那么有这么一种应用场景:
bool flag;
int function(void)
{
if (flag)
{
doSomething();
}
}
程序的本意是flag为true的时候执行doSomething(),假如flag是由某个中断更新为true的,那么程序在进入function时会将flag值拷贝到R0寄存器,然后访问R0寄存器的值,在判断if(flag)之前如果被中断打断,且flag被中断所更新,然而更新的是RAM内的真实值,function访问的却是R0寄存器的副本,所以在这种情况下就会丢失一个flag处理,因此flag需要用volatile来修饰。
可得出结论一:
当中断中去更新某个变量而由其他函数去检测这个变量时需要给这个变量加volatile。
volatile还有另一种用途,就是防止编译器优化一些语句。虽然编译器认为这些语句是废话,但实际我们认为这些语句是必要的,例如:
void delay(char n)
{
int i = 0XFFFF; //这里是要延时的时间
while(i--);
}
上面的程序本意是让程序延时一段时间,然后编译器会认为你i–了之后啥都没干,那我就直接把i减到0的“垃圾”语句剔除掉,反正你的最终目的是i=0。所以程序的表现结果就是:
void delay(char n)
{
int i = 0XFFFF;
while(i)
{
i = 0;
}
}
整个延时只执行了那么一次,不是我们期望的设计,所以得出结论二。
可得出结论二:
当函数中某个变量执行了无意义的修改但是这些修改又是我们所需要让程序运行的,将这些变量用volatile修饰。