它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。
简单地说就是防止编译器对代码进行优化.比如如下程序:
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器就不能像对待纯粹的程序那样对上述四条语句进行优化,只认为XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,则编译器会逐一的进行编译并产生相应的机器代码(四条).
volatile的语法和const是一样的。但是volatile的意思是:“在编译器认识的范围外,这个数据可以改变”。不知何故,环境正在改变数据(可能通过多任务、多线程或者中断处理),所以,volatile告诉编译器不要擅自作出有关该数据的任何假定,优化期间尤其如此。
就行建立const对象一样,程序猿也可以建立volatile对象,甚至还可以建立const volatile对象,这个对象不能被客户程序猿改变。但是,可以通过外部的代理程序改变。
#include "stdafx.h" class Comm { const volatile unsigned char byte; volatile unsigned char flag; enum { bufsize = 100 }; unsigned char buf[bufsize]; int index; public: Comm(); void isr() volatile; char read(int index) const; }; Comm::Comm(): index(0), byte(0), flag(0) { } void Comm::isr() volatile { flag = 0; buf[index++] = byte; if(index >= bufsize) index = 0; } char Comm::read(int index) const { if(index<0 || index>= bufsize) return 0; return buf[index]; } int _tmain(int argc, _TCHAR* argv[]) { volatile Comm port; port.isr();// OK //port.read(0); //Error read() not volatile return 0; }
就像const 一样,我们可以对数据成员和函数成员和对象本身使用volatile,可以对volatile对象调用volitile函数。
问题:1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:
int square(volatile int *ptr) { return *ptr * *ptr; }
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。
3). 这段代码是个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
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; }