關於修飾詞const

const在編程中經常遇到,包括全局變量和局部變量的修飾,函數參數的修飾,函數返回值的修飾等,下面我們來一步步的回顧下有關const關鍵詞的一些用意和疑問,並重新梳理一下const是何許人也?

1. const修飾的只讀變量必須在定義的同時初始化;
因爲如果沒有被賦初值,那麼變量被編譯器分配了一個空間,並且賦給默認的一個值,一般是很大的一個負數,當我們再次給這個const變量賦值的時候就會出現錯誤,這個變量是隻讀的,一旦被賦值了就不能再改變了。

 

2. case後面不可以是const修飾的只讀變量,因爲case之後只能是常量;

3. 函數的參數中的有const關鍵字,例如:
void fun(const int *a, const int *b)
{
    statement;
}
這個參數不是定義,是聲明而已,函數在調用的時候傳遞參數,同時給const變量賦值,這個過程是一個整體,而不是分化。另外,const告訴編譯器,a,b的值在函數體內不能被改變。聲明除了函數的參數外,還有一種關於const變量的聲明:extern const int a;注意這裏只是聲明,而不是定義。

 

4. const和define的區別:const效率更高;
const變量在編譯期間,編譯器通常不爲它分配內存空間,而是將他們保存在符號表中,例如:
#define LEN 3  //宏常量

const int MAX = 5; //此時並未將MAX放入內存中

....

int i = MAX; //此時爲MAX分配內存,以後不再分配
int j = LEN; //預編譯期間進行宏替換,爲LEN分配內存
int k = MAX; //不再爲MAX分配內存
int m = LEN; //再次進行宏替換,又一次爲LEN分配內存

 

5. const修飾的位置不同意義也不同:
(1)修飾一般簡單隻讀變量:
a. const int i = 2;等同於int const i = 2;
b. const int a[2] = {0,1};等同於int const a[2] = {0,1};
(2)修飾指針變量:
a. const int *p; // p可以變,p指向的對象不可變;
b. int const *p; // p可以變,p指向的對象不可變;
c. int *const p; // p不可以變,p指向的對象可以變;
d. const int *const p; //指針p和p指向的對象都不可以變;

6. 修飾函數返回值:
例如:const int fun(void);表示函數的返回值是不能被改變的,函數是一個只讀函數。


拓展:有關const的幾個疑問,從網上找了相關的答案,高人指點的很好,學習一下:
1.存儲位置:對於一個const類型的局部變量,真的是分配在“只讀數據段”?還是和普通局部變量一樣在棧上分配內存?
解答:只讀數據段僅是實現的其中一種方式,目的是在運行時令試圖修改const變量的行爲產生錯誤。由於C標準並沒有禁止對const變量的修改,而是規定屬於未定義行爲,因此一個實現對於試圖修改const的行爲如何處理都沒有違反標準,也就是說,無論把const變量放在只讀段也好,放在可被修改的地方也好(例如你說的棧),都是允許的行爲。

 
2.生命週期:“只讀數據段”,是和靜態變量一樣程序運行前就分配好內存,程序退出時才釋放內存,生命週期是整個程序運行時間?
解答:NO,只讀數據段與生命週期無關。


3.對於一個const類型的局部變量,如const int a=1;1這個值是在編譯期間就確定的,還是到運行時才確定的?
解答:這要分抽象語義和實現語義,對於抽象語義,a必定是運行時才確定的,抽象語義纔是a的本質;而對於一個實現,如果確定代碼的其它地方並沒有使用a的運行期信息,例如沒有使用a的地址等,編譯器也可以選擇將a的值隱式作爲字面值處理,即是說,編譯器在實現a的語義時可以靈活處理,只要能表現出a的抽象語義即可。


4.問題1,3對於const類型的全局變量呢?
解答:問題1的處理是一樣的,但全局變量不可能在棧中。而對於問題3,全局變量的值在編譯期是確定的。

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