volatile影响编译器编译的结果。如果没有volatile关键字,则编译器可能优化读取和存储,即在本次线程内,当读取一个变量时,为提高存取速度,编译器优化时会先把变量读取到一个寄存器中,以后再取变量值时,就直接从寄存器中取值。
volatile则提醒编译器,用它所定义的变量随时都有可能发生变化,因此编译后的程序每次需要存储或读取这个变量的时候,都需要直接从变量地址中读取数据。
【例14.20】分析下面函数能否实现延时的功能。
void delay(void){ int i; int result; for(i=0; i < 1863; ++i) result = 12* 35;}
【分析】不能。编译器知道12*35的结果为420,因此他没有做乘法而是通过优化处理直接给出“result=420”,从而关闭了计时功能。
如果使用两个变量,及声明
int num1 = 12,num2 = 35;
使用语句
result = num1 * num2;
也是不能实现计时的。一般与编译器的选择开关有关。这里针对一般的情况,因为优化器知道尽管该函数计算了result的值,但它仍然没有做任何处理。因此,无论result是否已经计算过,程序的执行都不会改变。于是,优化器发现如下循环:
for( i=0; i < 1863; ++i){ result = num1 * num2;}
就将其优化为:
for( i=0; i < 1863; ++i){ // Do nothing}
显然,不需要将Do nothing重复420次,因此程序就被优化为:
// No loop needed{ // Do nothing}
要阻止优化的方法是将result声明为volatile。但这也没有彻底解决问题,因为优化器很灵敏,它发现正在计算for循环体的
num1 * num2;
时,会把程序优化成只做一次乘法。
int register1 = num1 * num2;for( i=0; i < 1863; ++i){ result = register1;}
如果都使用volatile,就会克服这个问题。
//修改后的程序void delay(void){ int i; volatile int result; volatile int num1 = 12; volatile int num2 = 35; for( i=0; i < 1863; ++i) { result = num1 * num2; }}