以下參考了網上的一些資料並通過程序驗證。
注意,以下情況都是用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; }
結果:
我們看到,通過 int*p = (int*)(&a);這種方法,可以直接修改const常量對應的內存空間中的值,但是這種修改不會影響到常量本身的值,因為用到a的時候,編譯器根本不會去進行內存空間的讀取。這就是c++的常量折疊(constant folding),即將const常量放在符號表中,而並不給其分配內存。編譯器直接進行替換優化。除非需要用到a的存儲空間的時候,編譯器迫不得已才會分配一個空間給a,但之后a的值仍舊從符號表中讀取,不管a的存儲空間中的值如何變化,都不會對常量a產生影響。
但是在c中卻不是這樣.c沒有constant folding的概念,用constant定義一個常量的時候,編譯器會直接開辟一個內存空間存放該常量。不會進行優化。同樣的例子在c下面會產生不同的結果:
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的機制,使得常量的值跟對應的內存空間無關,從而保護了該常量值。
以上的例子是針對局部的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變量,不管是全局的還是局部,都是放在只讀數據區,所以無法用前面的方法來修改內存空間里面的值,編譯時就會報錯。