在C/C++ 編程中,volatile與const關鍵字一向容易讓人困惑,當然,新手可能從來不用,但是 在高質量和穩健的程序中,這兩個關鍵字 是相當重要的。
相比const,volatile關鍵字的發展(變化)較少,從C到C++的演變中,一直保持着 它的語義,因此,我們先從volatile來了解下,這兩個關鍵字
一、volatile
1.volatile 的基礎 認知:
volatile 的英文 釋義是 容易 揮發的,
作為 關鍵字,可以 記憶為 它修飾的 變量 是 不穩定的,可能被其他地方的某些方式改變,因此為了 獲取正確的值,編譯器 不該對其做優化,比如為了 獲取較快的 讀取速度,將它 放入寄存器中等,而是每次都要從它所在的內存中 讀取。
BS在 書中 對 volatile 的定義是:
A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.
volatile修飾符 意在暗示 編譯器,該被修飾的對象 通過該語言未指定的方式改變他的值,因此,積極的優化都應該被消除。
未指定的方式 ,比如 操作系統,硬件或者其他線程等。
遇到volatile修飾的變量,編譯器對訪問該變量的代碼 不再進行優化,從而可以提供對特殊地質的穩定訪問。
穩定的訪問的方式 是 ,系統總是重新從該 變量的 內存中讀取數據,即使 它 前面的 指令 剛剛 從該處 讀取過數據。
2.volatile 修飾指針
我們可以使用 volatile修飾 指針,比如
volatile char * myVolatileStr; char *volatile strVolatilePtr;
volatile 修飾 char* 和 *char 是 有較大區別的,和const修飾一樣,volatile可以將其修飾的 內存區域 聲明為 易揮發的,也可以將 指針變量本身聲明為 易揮發的。通常,有以下注意點:
注意:(1) 可以把一個非volatile int 賦給 volatile int,但是不能把非volatile對象賦給一個volatile對象。
(2) 除了基本類型外,對用戶定義類型也可以用volatile類型進行修飾。
(3) C++中一個有volatile標識符的類只能訪問它接口的子集,一個由類的實現者控制的子集。用戶只能用const_cast來獲得對類型接口的完全訪問。此外,volatile向const一樣會從類傳遞到它的成員。
3.volatile在 多線程中
在 多線程 中,有些變量是要用volatile關鍵字聲明的。當兩個線程都要用到某一個變量且該變量的值會被改變時,應該用volatile聲明,該關鍵字的作用是防止優化編譯器把變量從內存裝入CPU寄存器中。如果變量被裝入寄存器,那么兩個線程有可能一個使用內存中的變量,一個使用寄存器中的變量,這會造成程序的錯誤執行。volatile的意思是讓編譯器每次操作該變量時一定要從內存中真正取出,而不是使用已經存在寄存器中的值,
下面,來對比學習 下 const,
二、const
1.const基礎
在C++中,老手們建議 我們 盡可能的 多使用 const,但是 為啥呢?如果 面試官 問起,你就說,為了程序的穩健性,但是 這和問 鍛煉身體為啥呢,保衛祖國 ,沒什么 區別。
const 理論上 是 constant的簡寫,constant的英文釋義是 不變的;恆定的;經常的。但是 很多大神將它理解成了 只讀的,readonly,甚至覺得 要把這個關鍵詞 替換成readonly。這在gun編譯器中也是這么 提錯的,很有意思。
和volatile一樣,const也是對編譯器的約束(廢話),它明確的告訴 編譯器,const修飾的變量 是 不變的,如果出現了 其他地方的對其修飾值的改變,應該在編譯期間就報錯。這樣能大大提高程序的健壯性,當然,對於程序員,在編譯期間就發現錯誤本就是極好的。
2.const修飾局部變量
這是 最基本的用法,如
const int i = 5; int const i = 4;
3.const 與指針
const char* str; char * const str; char const* str; const char* const str; const char const* str;
4.const與引用
5. const修飾函數參數
void function(constintVar);//傳遞過來的參數在函數內不可以改變(無意義,因為Var本身就是形參)
void function(constchar*Var);//參數指針所指內容為常量不可變
void function(char*constVar);//參數指針本身為常量不可變(也無意義, 因為char* Var也是形參)
void function(constClass&Var);//引用參數在函數內不可以改變
void function(const TYPE&Var);//引用參數在函數內為常量不可變
6. const 修飾函數返回值
7. const修飾類對象/對象指針/對象引用
class AAA { void func1(); void func2()const; } const AAA aObj; aObj.func1();//× aObj.func2();//正確 const AAA* aObj =new AAA(); aObj->func1();// × aObj->func2();//正確
8. const修飾成員變量
class A { … constint nValue; //成員常量不能被修改 … A(int x): nValue(x){};//只能在初始化列表中賦值 }
9. const修飾成員函數
class A { … void function()const;//常成員函數, 它不改變對象的成員變量. 也不能調用類中任何非const成員函數。 }
10. const常量與define宏定義的區別
三、總結 分析