1. 程式人生 > >C++中字面值常量和字面值型別

C++中字面值常量和字面值型別

作者:zhaojia92 
來源:CSDN 
原文:https://blog.csdn.net/zhaojia92/article/details/50831436 
版權宣告:本文為博主原創文章,轉載請附上博文連結!


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

       常量表達式是指在編譯和執行過程中,該表示式的值不會改變,且編譯過程中可以立即得到其值的表示式。一部分const物件是常量表達式,由常量表達式初始化的const物件也是常量表達式。常量表達式在程式執行時不會改變,即使一個程式多次啟動或外部引數發生變化,該值也不會改變。編譯器在編譯優化時可能把常量表達式直接替換為立即數,具體要看編譯環境。一般來講,字面值常量屬於常量表達式。

       並非所有const物件都是常量表達式,const僅標記物件為只讀屬性,該物件在初始化後無法再改變。如果const物件所賦初值在編譯階段就可確定,那麼此const物件才是常量表達式。const物件和儲存位置也沒有必然聯絡,常量可以分佈在棧、堆、靜態儲存區中。對於宣告在函式體內的const常量,如果沒有被編譯優化掉,該常量儲存在棧中。全域性的const常量儲存在全域性儲存區。

      C++中允許將變數宣告為constexpr型別以使編譯器在編譯時檢查該變數是否是常量表達式。宣告為constexpr的物件一定是常量表達式。且初始化必須用常量表達式。

例如:

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

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

   constexpr int c = a+b; //編譯器可以在編譯時期可以確定其值

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

   constexpr int e = getsize();  //error! 將會報錯

      字面值的型別根據字面值表達形式不同而不同,編譯器根據字面值形式推斷字面值的型別。字面值多數為算術型別。自定義類、IO類不屬於該型別。

      對於指標字面值,其只有nullptr和NULL。指標也可以是constexpr的常量表達式,表示該指標為const且指向在編譯時確定。不是所有的頂層const指標都是constexpr的。只有那些在編譯時就確定地址指向的const指標才是constexpr。因此nullptr、NULL、指向固定地址的指標是constexpr的。


      對於顯式指出的字串常量,其儲存在常量儲存區中,例如:

      const char *const str1 = "hello"; //

      const char *const str2 = "hello"; //“hello"儲存在常量儲存區

      constexpr const char *str = str1; //constexpr,編譯時確定的指標str

      assert(str1 == str2); //str1和str2指向相同地址

      此時的str1和str2指標都是constexpr的。那麼,如何判斷指標是否指向固定地址呢? 

      程式在記憶體中的組織形式是段,有堆疊段、資料段和程式碼段。對於資料指標指向資料,函式指標則指向某個程式碼。

       對於定義在函式體外的變數,其指標是constexpr的;此類變數要佔用資料段,而程式執行時,程式碼段和資料段大小位置均不會改變,因此編譯器可以確定地址指向,是constexpr的。此外,函式內部定義的static靜態變數,也會在資料區使用固定地址,因此指標也是constexpr的。對於定義在函式內部的變數,由於要在棧中開闢記憶體空間,而棧的情況要看程式執行狀態,因此這類變數沒有確定的地址,其指標不是constexpr的。程式碼段不會改變,函式指標也是constexpr的。

       const/constexpr常量表達式可能在編譯時直接替換為立即數;但也可能被編譯為const物件,程式執行時佔用記憶體空間。const/constexpr是否被替換為立即數或生成物件取決於編譯環境和語義解析,語義不允許替換的地方便生成const物件,就如inline函式一樣,不是所有inline函式都被替換。