volatile的意思是易變的、可變的,作用是限制編譯器優(yōu)化某些變量。首先看一段C51程序:
Keil在優(yōu)化級別是為8時得到如下匯編代碼(部分未列出):
可以看到,變量d的值賦給x,y,z時,只有x中是直接讀取的d中數(shù)值,而y=d,z=d則直接將寄存器中的數(shù)值賦給y,z。若在此過程中,變量d的值被改變(比如d是一個硬件寄存器),則y,z變量中得到的數(shù)據(jù)將是錯誤的,因此在某些應用中程序存在隱患。
這類問題并不是編譯器的問題。由于訪問內部寄存器比訪問RAM速度塊,因此編譯器在編譯類似程序時,會對程序進行優(yōu)化,除第一次編譯變量所在在連續(xù)讀取一個變量時,編譯器為了簡化程序,只要有可能就會把第一次讀取的值放在ACC或Rx中,在以后的讀取該變量的值時就直接使用第一次的讀取值。如果該變量的值在此過程中已經被外設(如讀取外部設備端口時經常將外設端口看作一外部RAM地址)或其他程序(如中斷服務程序)所改變,可能就會出錯。為了解決這類問題,常用的方法就是降低編譯器的優(yōu)化級別或者使用volatile關鍵字。顯然降低優(yōu)化級別不是所期望的,因此用volatile關鍵字修飾相關變量很有必要。
上文中的例子將d加上volatile關鍵字后,如下:
重新編譯得到的代碼(部分未列出)如下:
可以看這此y,z變量的值是從d的存儲區(qū)中讀取的。這主要是由編譯器的優(yōu)化早成的,而不是編譯器的錯誤。用volatile變量對變量d修飾后,編譯器不對這個變量的操作進行優(yōu)化,代碼的執(zhí)行達到期望的目的。
一般說來,volatile關鍵字用在如下的幾個地方。
(1)中斷服務程序中修改的供其他程序檢測的變量需要加volatile。
(2)多任務環(huán)境下各任務間共享的標志應該加volatile。
(3)存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能有不同意義。