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


以下參考了網上的一些資料並通過程序驗證。

注意,以下情況都是用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變量,不管是全局的還是局部,都是放在只讀數據區,所以無法用前面的方法來修改內存空間里面的值,編譯時就會報錯。

 

 

 


免責聲明!

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



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