c和c++關於const的一些區別

如下參考了網上的一些資料並經過程序驗證。c++

注意,如下狀況都是用gcc和g++編譯器獲得的結果,用vs編譯器又會有所不一樣。數組

如下說下c和c++中const定義的常量的一些區別:函數

c++中用const定義了一個常量後,不會分配一個空間給它,而是將其寫入符號表(symbol table),這使得它成爲一個編譯期間的常量,沒有了存儲與讀內存的操做,使得它的效率也很高。可是const定義的常量本質上也是一個變量,是變量就會有地址,那麼何時會分配內存?看看下面的代碼:優化

int main(){
    const int a  = 2;
    int* p = (int*)(&a);
    *p = 30;
    cout<<&a<<endl; 
    cout<<p<<endl;  
    cout<<a<<endl;
    cout<<*p<<endl;
}

結果:spa

咱們看到,經過 int*p = (int*)(&a);這種方法,能夠直接修改const常量對應的內存空間中的值,可是這種修改不會影響到常量自己的值,由於用到a的時候,編譯器根本不會去進行內存空間的讀取。這就是c++的常量摺疊(constant folding),即將const常量放在符號表中,而並不給其分配內存。編譯器直接進行替換優化。除非須要用到a的存儲空間的時候,編譯器無可奈何纔會分配一個空間給a,但以後a的值仍舊從符號表中讀取,無論a的存儲空間中的值如何變化,都不會對常量a產生影響。code

可是在c中卻不是這樣.c沒有constant folding的概念,用constant定義一個常量的時候,編譯器會直接開闢一個內存空間存放該常量。不會進行優化。一樣的例子在c下面會產生不一樣的結果:blog

 1 int main()
 2 {
 3     const int a  = 2;
 4     int* p = (int*)(&a);
 5     *p = 30;
 6     printf("%x\n",&a);
 7     printf("%x\n",p);
 8     printf("%i\n",a);
 9     printf("%i\n",*p);
10     return 0;
11 }

結果:內存

咱們看到,在c裏面,一個被const定義爲常量的值,冠冕堂皇地被修改了,並且編譯器沒有報任何錯誤 !編譯器

若是咱們進一步深刻能夠發現,對於以上兩個例子來講,a都是定義在某個函數以內的(好比main()函數),無論是c仍是c++,本質上都只是將其當成一個普通的局部變量來對待,都只是在棧上分配空間。因此const根本就不能起到阻止修改其內存空間的做用,一個合法的強制類型轉換就能夠輕鬆搞定。c++比c好的地方就在於使用了constant folding的機制,使得常量的值跟對應的內存空間無關,從而保護了該常量值。it

以上的例子是針對局部的const常量而言,對全局的const變量,c++仍舊採用constant folding策略,故如下代碼是行得通的:

//global variable
const int a = 3;
int arr[a];

可是c會報錯: error: variably modified 'arr' at file scope, 緣由在於gcc認爲a只是一個普通的全局變量,而變量是不能用來指定數組的長度的。固然,這是針對全局數組而言,若是是局部的數組的話,就算是int a = 3; int arr[a];這種都是能夠的,由於c裏面還有一種叫變長數組的東西(我暈~,貌似由於二者的實現機制不同,這個要再看看)

另外,對於a,在c和c++中若是咱們仍然用int *p = (int*)(&a);這種方法來修改它內存中的值,編譯時不會報錯,可是運行時會報段錯誤,由於a是放在只讀的全局數據區中,修改該區中的數據會引起段錯誤。

 

在vs編譯器下:

1.不支持變長數組,一個變量除非被聲明爲const,不然不能用來聲明數組的長度。

2.const變量,無論是全局的仍是局部,都是放在只讀數據區,因此沒法用前面的方法來修改內存空間裏面的值,編譯時就會報錯。

相關文章
相關標籤/搜索