在C中,const不是常量,只能說是一個不能改變的變量(注意是變量),C編譯器不能把const看成看成一個編譯期間的常量,因為他在內存中有分配,C編譯器不知道他在編譯期間的值。所以不能作為數組定義時的下標,因為它必須為常量。
在C中,const int a;是可以的,因為這只是聲明一個變量,告訴編譯器,我這里是聲明,指明在別的地方有內存分配。但在C++中這樣寫是不正確的,C++中const默認是內部鏈接,C中默認是外部鏈接,為了起到和c語言一樣的效果,C++需要將const修飾為extern,因為extern優先級高於const,所以變量會被變為extern外部鏈接,起到和C語言一樣的效果。[ (1) 內連接:編譯器只對正被編譯的文件創建存儲空間,別的文件可以使用相同的表示符或全局變量.C/C++中內連接使用static關鍵字指定.(2) 外連接:所有被編譯過的文件創建一片單獨存儲空間.一旦空間被創建,連接器必須解決對這片存儲空間的引用.全局變量和函數使用外部連接.通過extern關鍵字聲明,可以從其他文件訪問相應的變量和函數. ] 通俗的講:在c++ 中const 對象默認為文件的局部變量。與其他變量不同,除非特別說明,在全局作用域聲明的 const 變量是定義該對象的文件的局部變量。此變量只存在於那個文件中,不能被其他文件訪問。通過指定 const 變更為 extern,就可以在整個程序中訪問 const 對象。
C++中是否為const分配內存空間要看具體情況,如果被聲明為extern或者取const變量地址,就需要為const變量分配空間。
當在自己的文件中使用const的時候,C++不會為const常量分配空間,因為這是一種優化措施,沒有必要浪費空間去存儲一個常量,此時const int a=5 就相當於#define a 5,當在其他文件使用的時,需要分配內存,同樣在程序內部引用的時候,也需要分配內存,因為這兩者都是采用尋址的技術去使用的,不分配內存就沒有地址。C++中定義常量的時候不再采用define,因為define只做簡單的宏替換,並不提供類型檢查。
C++中用const定義了一個常量后,不會分配一個空間給它,而是將其寫入符號表(symbol table),這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。但是const定義的常量本質上也是一個變量,是變量就會有地址,那么什么時候會分配內存?
1 int main() 2 { 3 const int a = 2; 4 int* p = (int*)(&a); 5 *p = 30; 6 cout << &a << endl; 7 cout << p << endl; 8 cout << a << endl; 9 cout << *p << endl; 10 return 0; 11 } 12 13 /*運行結果: 14 ----------- 15 010FF958 16 010FF958 17 2 18 30 19 ----------- 20 */
通過 int*p = (int*)(&a);這種方法,可以直接修改const常量對應的內存空間中的值,但修改不會影響到常量本身的值,因為用到a的時候,編譯器根本不會去進行內存空間的讀取。這就是C++的常量折疊constant folding,即將const常量放在符號表中,而並不給其分配內存。編譯器直接進行替換優化。除非需要用到a的存儲空間的時候,編譯器迫不得已才會分配一個空間給a,但之后a的值仍舊從符號表中讀取,不管a的存儲空間中的值如何變化,都不會對常量a產生影響。
但是在C語言中卻不是這樣,C沒有constant folding的概念,用const定義一個常量的時候,編譯器會直接開辟一個內存空間存放該常量。不會進行優化。同樣的例子在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 } 12 13 /*運行結果 14 ------------ 15 61fe14 16 61fe14 17 30 18 30 19 ------------*/
C中,一個被const定義為常量的值,卻能被修改,而且編譯器不報任何錯誤 。進一步深入可發現,對於以上兩個例子來說,a都是定義在某個函數之內的(比如main()函數),不管是C還是C++,本質上都只是將其當成一個普通的局部變量來對待,都只是在棧上分配空間。所以const根本就不能起到阻止修改其內存空間的作用,一個合法的強制類型轉換就可以輕松搞定。C++比C好的地方就在於使用了constant folding的機制,使得常量的值跟對應的內存空間無關,從而保護了該常量值。
1 const int a = 3; 2 int arr[a];
但C會報錯: error: variably modified 'arr' at file scope, 原因在於GCC認為a只是一個普通的全局變量,而變量是不能用來指定數組的長度的,這是針對全局數組而言。但如果是局部的數組的話,就算是int a = 3; int arr[a];這種都是可以的,若在C和C++中如果我們仍然用int *p = (int*)(&a);這種方法來修改它內存中的值,編譯時不會報錯,但是運行時會報錯誤,因為a是放在只讀的全局數據區中,修改該區中的數據會引發段錯誤。