volatile修饰的变量表示是随时可以发生变化的,因此当编译器用到这个值的时候会重新去调用其数值,而不是使用保存在寄存器的备份。Volatile一般来修饰寄存器变量,因为寄存器里面存数的数据会经常发生变化。Volatile只是一个修饰关键字因此可以用数据类型放在前边修饰比如:const volatile a;表示a是一个volatile类型的常量,说是常量是因为在程序运行中程序不能更改这个数值,但是它可能会意想不到的发生改变。在头文件中常来定义寄存器变量,比如:
#define PWMC (*(unsigned int volatile xdata *)0xfff0)
#define PWMCH (*(unsigned char volatile xdata *)0xfff0)
#define PWMCL (*(unsigned char volatile xdata *)0xfff1)
#define PWMCKS (*(unsigned char volatile xdata *)0xfff2)
通过指针来定义寄存器变量。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1) 并行设备的硬件寄存器(如:状态寄存器)
2) 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3) 多线程应用中被几个任务共享的变量
这个问题是区分C程序员和嵌入式系统程序员的最基本的点。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatile变量。不懂得volatile的使用将会带来灾难。
解释:
在我们编译程序的时候,现代编译器总会去做一些优化,优化之一就是避免每次去读内存的值,我们知道,CPU每次去读内存的时候是很耗时的操作,所以编译器为了提高执行效率,往往就会去做一些优化。
在上面这个例子来看,没多大毛病,但是,问题的核心在于,如果我们将这个程序片段放到一个多线程的环境,或者一个嵌入式系统中与中断处理程序相关的一些程序代码的时候,那意外就产生了,在休眠100ms的这个时间段内,obj的值很可能被其他线程比改变,那么休眠完毕后赋值给b的值也就应该发生变化,但是没有给obj添加volatile关键字,编译器自动优化了,此时的obj的值并没有发生改变,b所得到的值不是一个正确的值。
所以,为了避免这个情况,我们就可以使用volatile来修饰obj变量,告诉编译器不要“自作聪明”来对这个变量进行优化处理,取消也可以说是保护现场。
volatile这个关键字在嵌入式或者多线程使用较多。
另外const和volatile的区别: