ZHCUAV8W january 1998 – march 2023 66AK2E05 , 66AK2H06 , 66AK2H12 , 66AK2H14 , AM1705 , AM1707 , AM1802 , AM1806 , AM1808 , AM1810 , AM5K2E04 , OMAP-L132 , OMAP-L137 , OMAP-L138 , SM470R1B1M-HT , TMS470R1A288 , TMS470R1A384 , TMS470R1A64 , TMS470R1B1M , TMS470R1B512 , TMS470R1B768
C/C++ 編譯器在所有模式下都支持 volatile 關(guān)鍵字,但 。此外,在 C89、C99、C11 和 C++ 的寬松 ANSI 模式下支持 __volatile 關(guān)鍵字。
volatile 關(guān)鍵字指示編譯器如何訪問(wèn)變量,這要求編譯器不得投機(jī)取巧地優(yōu)化涉及該變量的表達(dá)式。例如,外部程序、中斷、另一個(gè)線程或外圍設(shè)備也以訪問(wèn)該變量。
編譯器會(huì)使用數(shù)據(jù)流分析來(lái)確定訪問(wèn)是否合法,從而盡可能消除冗余的存儲(chǔ)器訪問(wèn)。不過(guò),一些存儲(chǔ)器訪問(wèn)可能在編譯器未看到的方面比較特殊,在這類(lèi)情況下,您應(yīng)當(dāng)使用 volatile 關(guān)鍵字來(lái)防止編譯器優(yōu)化掉某些重要內(nèi)容。對(duì)于已聲明為 volatile 的變量,編譯器不會(huì)優(yōu)化掉對(duì)該變量的任何訪問(wèn)。volatile 讀取和寫(xiě)入的次數(shù)將與 C/C++ 代碼中的完全相同,不多不少而且順序也完全相同。
任何可能由明顯程序控制流程外部的事物(例如中斷服務(wù)例程)進(jìn)行修改的變量必須聲明為 volatile。這會(huì)告訴編譯器,中斷函數(shù)可能會(huì)隨時(shí)修改該值,因此編譯器不應(yīng)執(zhí)行會(huì)更改該變量的編號(hào)或訪問(wèn)順序的優(yōu)化。這就是 volatile 關(guān)鍵字的主要用途。在下述示例中,循環(huán)旨在等待位置被讀取為 0xFF :
unsigned int *ctrl;
while (*ctrl !=0xFF);不過(guò),在此示例中,*ctrl 是循環(huán)不變量表達(dá)式,因此循環(huán)會(huì)優(yōu)化為單個(gè)存儲(chǔ)器讀取。若要獲取所需結(jié)果,應(yīng)將 ctrl 定義為:
volatile unsigned int *ctrl;其中,*ctrl 指針旨在引用一個(gè)硬件位置,例如中斷標(biāo)志。
訪問(wèn)表示存儲(chǔ)器映射外圍設(shè)備的存儲(chǔ)器位置時(shí),也必須使用 volatile 關(guān)鍵字。此類(lèi)存儲(chǔ)器位置可能會(huì)以編譯器無(wú)法預(yù)測(cè)的方式更改值。這些位置可能會(huì)在被訪問(wèn)時(shí)、或者當(dāng)其他存儲(chǔ)器位置被訪問(wèn)時(shí)或者出現(xiàn)某些信號(hào)時(shí)發(fā)生改變。
在調(diào)用 setjmp 的函數(shù)中,如果局部變量的值需要在發(fā)生 longjmp 時(shí)保持有效,則 volatile 也必須用于局部變量。
#include <stdlib.h>
jmp_buf context;
void function()
{
volatile int x = 3;
switch(setjmp(context))
{
case 0: setup(); break;
default:
{
/* We only reach here if longjmp occurs.因?yàn)?x 的生命周期在 setjmp 之前開(kāi)始并持續(xù)至 longjmp,C 標(biāo)準(zhǔn)要求將 x 聲明為 "volatile"。*/
printf("x == %d\n", x);
break;
}
}
}