最近在看程序員面試寶典,看到const這塊感受有很大疑惑,查了不少資料,能夠總結以下:程序員
1.在C語言中面試
在C語言中,const修飾的變量不具備常量的特性,只是一個不可修改的變量,實質上仍然是變量,在編譯期間沒法知道它的值,不能夠用做數組下標。數組
2.在C++中 函數
在C++中,const就有很大不同,C++中鼓勵使用const來替代#define,在C++中對const定義的變量分爲兩種狀況:學習
狀況1(在.rodata段分配空間):優化
若是const用在全局或者使用了static關鍵字說明,例如extern const int i=10,static const int i=10。那麼這個i就是一個常量(網上有人說真正意義上的常量),而且該常量是存放在.rodata段的,是沒法經過取地址方式去修改的(具體狀況見狀況2),修改會報段錯誤。spa
狀況2(不在.rodata段分配空間):調試
若是const用在局部而且沒有使用static關鍵字,例如在main函數裏面const int i=10*2+1,在這種狀況下,若是對該常量:1)賦值是常量表達式(沒有其它變量或者須要外界輸入的值);2)不對該常量進行一些取地址相似的操做(&),就不會對i分配空間,僅僅是將其放在符號表中;不然,就會對i分配空間,並且這個空間是在棧上的,不一樣於全局或是靜態的是分配在.rodata段上的。另外,注意,利用編譯器反彙編的時候,可能會有一些假象,例如,在DEBUG模式下面的反彙編,編譯器生成彙編代碼爲了能更好的調試,因此不管如何都會分配空間給const常量,可是若是你打開編譯器的O2優化選項的話,就不會分配空間了。內存
不過,不論分不分配空間,只要該常量的賦值是常量表達式(沒有其它變量或者須要外界輸入的值),編譯器都會作一個優化,叫作常量摺疊(constant folding),簡單來講,就是編譯的時候,任何用到i的地方,都會直接用21去替換i。ci
a.有常量摺疊
若是i的賦值是常量表達式(沒有其它變量或者須要外界輸入的值),即i的值不須要訪問存儲空間來肯定,那麼程序中任何出現i的地方就已經在編譯期間被替換,即便經過取地址來修改這個值,也是至關於改變了一個副本而已,以下:
const int i=1; int *p=(int *)&i; *p=2; cout<<*p<<endl<<i<<endl; 輸出結果: 2 1 |
這說明,i的值是肯定的狀況下,程序中任何出現i的地方都被1替換了。
b.無常量摺疊
另外一種狀況,若是賦值不是常量表達式,這時是須要訪問存儲區域才能獲得確切值的,這種狀況並不會有"常量摺疊",以下:
int i=10; const char gc = cin.get(); //或者const char gc = i都是同樣的 char *t = (char *)&gc; *t += 2; cout << *t <<endl << gc << endl; 輸如:a 輸出: c c |
從上面這個狀況能夠看出,雖然gc是局部的const,可是它的值是不肯定的,是須要用戶輸入的,所以會爲gc在棧中分配空間,而且由於gc的值不肯定,它不能獲得常量摺疊帶來的優化。程序中使用gc的地方,必須直接到存儲區域去訪問才能獲得值,因此*t和gc的值是保持一致的。
無常量摺疊的狀況下,必定是分配了內存空間的,由於無常量摺疊的本質就是值不肯定,須要到內存中獲取。而有常量摺疊的狀況下,內存空間可能分配了,也可能沒分配,若是分配了,那是由於對該常量進行了取地址相關的操做。
volatile關鍵字:
除此以外,volatile關鍵字也可以屏蔽掉常量摺疊,以下:
volatile const int i=1; int *p=(int *)&i; *p=2; cout<<*p<<endl<<i<<endl; 輸出結果: 2 2 |
上面是我查閱資料綜合獲得的狀況,具體來講,const使用狀況可分爲全局和局部(static關鍵字是一個因素),局部下又可分爲分配內存與不分配內存、有常量摺疊和無常量摺疊,分不分配內存取決因而否要對該常量進行地址相關的操做(如&或者直接從內存取值),有沒有常量摺疊取決於需不須要直接從內存中取值。
有不少不足還請各位大神指出,你們相互學習相互進步,勿噴就好,謝謝啦
轉載請說明出處