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