天天看點

才搞清楚常量的存儲位置

 一個形如42的值被稱為字面值常量。字面值常量的形式和值決定了常量的類型。例如0x42是16進制表示的整型常量。‘a'是char型字面值。字面值常量顧名思義由字面意思表示,是常量。字面值常量在程式中是直接表示的,整型直接寫出大小,字元直接寫出字元。一個字面值常量在編譯時被直接解析為立即數,編譯器内部維護字面值常量的類型。

      常量表達式是指在編譯過程中,該表達式的值不會改變,且編譯過程中可以立即得到結果的表達式。一部分const對象是常量表達式,由常量表達式初始化的const對象也是常量表達式。常量表達式在程式運作時不會改變,即使一個程式多次啟動或外部參數發生變化,該值也不會改變。編譯器在編譯時可能把常量表達式直接替換為立即數,具體要看編譯環境。一般來講,字面值常量屬于常量表達式。

      C++中允許将變量聲明為constexpr類型以使編譯器在編譯時檢查該變量是否是常量表達式。聲明為constexpr的變量一定是常量表達式。且初始化必須用常量表達式。

例如:

   const int a = 12;    a是常量表達式

   const int b = a+1;  b也是常量表達式

   const int c = getsize();   c不是常量表達式,編譯器編譯時無法确知getsize()的執行結果。

   constexpr int c = getsize();  将會報錯

      字面值類型是指編譯時就能得到結果的類型,具體包括算術類型、引用和指針。自定義類、IO類不屬于該類型。字面值類型的對象有嚴格的要求,字面值類型是那些具有常量表達式屬性的對象的類型。例如:字面值常量是算術類型。對于引用和指針,其限定比較嚴格。不是所有的指針都是常量表達式。隻有那些在編譯時就确定位址指向的指針才是常量表達式,引用同理。是以nullptr、NULL、指向固定位址的指針是字面值類型。那麼,如何判斷指針是否指向固定位址呢?

      程式在記憶體中的組織形式是段,有堆棧段、資料段和代碼段。對于資料指針指向資料,函數指針則指向某個代碼。

才搞清楚常量的存儲位置

資料段包括全局/靜态存儲區,常量存儲區。對于全局變量,其指針是constexpr的;此類變量要占用資料段(全局存儲區),而程式運作時,代碼段和資料段大小位置均不會改變,是以編譯器可以确定位址指向,是constexpr的。此外,函數内部定義的static靜态變量,也會在資料區(靜态存儲區)使用固定位址,是以指針也是constexpr的。對于定義在函數内部的變量,由于要在棧中開辟記憶體空間,而棧的情況要看程式運作狀态,是以這類變量沒有确定的位址,其指針不是constexpr的。代碼段不會改變,函數指針也是constexpr的。

2016/09/24--------------------------------------------------------------------------------------------------

對常量的了解還是有誤區,以const int i=10;為例,之前一直誤認為i是存儲在常量存儲區裡的,大錯特錯!因為無法解釋const棧變量的存儲位置。實際上并不存在常量存儲區,隻有全局/靜态存儲區。const類型的存儲跟一般的變量沒有差別,在外部定義的存儲在全局資料區,static的存儲在靜态資料區,在函數内部定義的存儲在棧,const跟非const存儲上沒差別,隻不過是read only的。

參考 http://bbs.csdn.net/topics/340089467