volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值,即不是从寄存器里取备份值,而是去该地址内存存储的值.
简单地说就是防止编译器对代码进行优化.比如如下程序:
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,编译器会逐一的进行编译并产生相应的机器代码(产生四条代码).下面是volatile变量的几个例子:
1) 并行设备的硬件寄存器(如:状态寄存器);
2) 一个中断服务子程序中会访问到的非自动变量;
3) 多线程应用中被几个任务共享的变量;
这是区分C程序员和嵌入式系统程序员的最基本的问题:嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所有这些都要求使用volatile变量。不懂得volatile内容将会带来灾难。
1) 一个参数既可以是const还可以是volatile吗?解释为什么。
答案:
1) 是的。一个例子是只读的状态寄存器(计算机系统的核心部件——运算器的一部分,状态寄存器用来存放两类信息:一类是体现当前指令执行结果的各种状态信息(条件码),如有无进位(CF位)等;另一类是存放控制信息(PSW:程序状态字寄存器),如允许中断(IF位)等)。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。没问题,const和volatile这两个类型限定符不矛盾。const表示(运行时)常量语义:被const修饰的对象在所在的作用域无法进行修改操作,编译器对于试图直接修改const对象的表达式会产生编译错误。volatile表示“易变的”,即在运行期对象可能在当前程序上下文的控制流以外被修改(例如多线程中被其它线程修改;对象所在的存储器可能被多个硬件设备随机修改等情况):被volatile修饰的对象,编译器不会对这个对象的操作进行优化。一个对象可以同时被const和volatile修饰,表明这个对象体现常量语义,但同时可能被当前对象所在程序上下文意外的情况修改。
2) 一个指针可以是volatile吗?解释为什么。
是的。尽管这并不很常见。一个例子是当一个中断服务子程序修该一个指向一个buffer的指针时。
3) 下面的函数有什么错误:
intsquare(volatile int *ptr)
{
return *ptr * *ptr;
}
这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
intsquare(volatile int *ptr)
{
inta,b;
a =*ptr;
b =*ptr;
returna * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
longsquare(volatile int *ptr)
{
int a;
a =*ptr;
returna * a;
}