const分別在C和C++語言裏的含義和實現機制

const分別在C和C++語言裏的含義和實現機制
 

const的含義

       簡單地說:const在c語言中表示只讀的變量,而在c++語言中表示常量.

C語言

const是constant的縮寫,是恆定不變的意思,也翻譯爲常量,但是很多人都認爲被const修飾的值都是常量,其實這是不精確的.因爲,精確來說應該是隻讀的變量,其值在編譯的時候不能被使用,因爲編譯器在編譯的時候不知道其存儲的內容.或許當初這個關鍵字應該被替換爲readonly.

C語言中const定義的變量只是給出了對應的內存地址,而不是像#define一樣給出的是立即數,所以,const定義的只讀變量在程序運行過程中只有一個備份(因爲它是全局的只讀變量,存放在靜態區),而#define定義的宏變量在內存中有若干個備份.

c++語言:

const是C++中常用的類型修飾符,常類型是指使用類型修飾符const說明的類型,常類型的變量或對象的值是不能被更新的.

         C++引入const的初始目的是爲了取代預編譯指令,消除他的缺點,同時繼承它的優點.<缺點:只是簡單值和代碼的替代,缺乏類型的檢測機制,安全性不好;優點有三:1.避免意義模糊的數字出現,清晰程序語義2.方便參數的調整和修改,3.提高程序執行效率,因爲不需要爲常量分配空間>

問題出來了:爲什麼const能取代預定義語句?

1.   首先,以const修飾的變量和對象具有不可變性,這是它能取代預定義語句的基礎.

2.   第二,很明顯,它同樣能避免意義模糊的數字定義,也可以方便地進行參數的調整與修改.

3.   第三,c++編譯器通常不爲普通const常量(普通是指內置類型,不包括結構體等類型)分配存儲空間,只是把它們保存在符號表中(注意:c語言中則會爲const變量分配存儲空間),這使得它們成爲了編譯期間的常量,沒有了存儲和讀內存的操作,使得它的效率非常高,同時,也是它能取代預定義語句的重要基礎.

4.   最後,const定義也能像普通的變量定義一樣,它會由編譯器對它進行類型的安全檢查,消除了預定義語句帶來的安全隱患.

我們使用一張表來總結const的作用:

No.
作用
說明
參考代碼

1
可以定義const常量
 
const int Max = 100;

2
便於進行類型檢查
const常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查,而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換時可能會產生意料不到的錯誤
void f(const int i) { .........}
      //對傳入的參數進行類型檢查,不匹配進行提示

3
可以保護被修飾的東西
防止意外的修改,增強程序的健壯性。
void f(const int i) { i=10;//error! }
      //如果在函數體內修改了i,編譯器就會報錯

4
可以很方便地進行參數的調整和修改
同宏定義一樣,可以做到不變則已,一變都變
 

5
爲函數重載提供了一個參考
 
class A
{
           ......
  void f(int i)       {......} //一個函數
  void f(int i) const {......} //上一個函數的重載
           ......
};

6
可以節省空間,避免不必要的內存分配
const定義常量從彙編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝
#define PI 3.14159         //常量宏
const doulbe  Pi=3.14159;  //此時並未將Pi放入ROM中
              ......
double i=Pi;   //此時爲Pi分配內存,以後不再分配!
double I=PI;  //編譯期間進行宏替換,分配內存
double j=Pi;  //沒有內存分配
double J=PI;  //再進行宏替換,又一次分配內存!

7
  提高了效率
編譯器通常不爲普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成爲一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高
 

const的實現機制

const究竟是如何實現的呢?對於聲明爲const的內置類型,例如int,short,long等等,編譯器會如何實現const的本意?那麼對於非內置類型是否也是與內置數據類型一樣處理呢,例如對於結構體類型則會怎樣處理呢?下面通過幾個小例子來說明這些問題:
C語言const示例:


const int i=10;
int *p=(int *)(&i);
*p=20;
printf("i=%d *p=%d \n",i,*p);


猜一猜輸出結果是什麼? i=20 *p=20
C++語言const示例1:


const int i=10;
int *p=const_cast<int *>(&i);
*p=20;

cout<<"i="<<i<<"*p="<<*p<<endl;


輸出結果是 i=10 *p=20
C++語言const示例2:


struct test{
int j;
char tmp;
test()
{
j=30;
tmp='a';
}
};
int main(int argc, char* argv[])
{
const struct test t1;
int *q=(int *)(&t1.j);
*q=40;
cout<<"j="<<t1.j<<"*q="<<*q<<endl;
return 0;
}


輸出結果是 j=40 *q=40

示例結果分析
看到上面三組輸出結果,我們可以分析兩個問題:

問題1:C語言和C++語言中的const究竟表示什麼?

問題2:const的實現機制究竟是怎樣的?


問題1,對於const int類型的變量i,C語言中通過指針p修改了值後,i變成了20;而在C++中,通過指針p修改了值後,i仍然是10。
問題2,C++語言中 const struct test的元素j通過指針q被改變了,爲何const int 與 const struct test的反應機制不同?

針對問題1,我們知道C語言中const表示只讀的變量,既然把const看成是變量,那麼其在內存中就會有存儲他的空間,並且可以通過指針間接的改變該內存空間的值,當通過指針p改變該內存中的值後,再獲取i的值的時候,會訪問該空間,得到的是被改變後的值。而C++把const看做常量,編譯器會使用常數直接替換掉對i的引用,例如cout<<i; 會理解成cout<<10; 並不會去訪問i的內存地址去取數據,這裏有點像是C語言裏的宏#define i 10。因此C++裏i會輸出10,而*p會輸出20.

針對問題2,C++語言中只是對於內置數據類型做常數替換,而對於像結構體這樣的非內置數據類型則不會。因爲結構體類型不是內置數據類型,編譯器不知道如何直接替換,因此必須要訪問內存去取數據,而訪問內存去取數據必然會取到被指針q改變後的值,因此會造成與C++中const int類型完全不一樣的處理模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章