const在C與C++中的區別


  在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的機制,使得常量的值跟對應的內存空間無關,從而保護了該常量值。

  以上的例子針對局部的const常量而言,對全局的const變量,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是放在只讀的全局數據區中,修改該區中的數據會引發段錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM