#define、const、constexpr


const 、#define、constexpr

  • #define

    define是C語言中的宏,拿來進行文本替換。如,#define number 100,在程序的預處理階段,會將程序中,所有出現number的地方,使用100來進行替換。

    缺點:這個是在預處理階段就完成的文本替換,與編譯階段是不同階段,不會進行類型檢查。

  • const
    i. 編譯時的值替代 --- const限定的變量,在編譯階段,編譯器會進行常量折疊的一些優化操作。所謂常量折疊,就是化簡常量表達式,即當遇到const限定的變量時,會用相應的值進行替換,使其變為一個立即數。當然,不是所有情況都能進行常量折疊,如對常量進行取地址操作。
    eg:

    int main(){
      const int a = 2;
      int *ptr = const_cast<int *>(&a);//改變常量屬性
      *ptr = 5;
      printf("a = %d\n" ,a);//此處進行常量折疊
      printf("&a = %x\n", &a);
      printf("*ptr = %d\n",*ptr);
      printf("ptr = %x\n",ptr);
      printf("a = %d\n" ,a);////此處進行常量折疊
      printf("&a = %x\n", &a);
    
      return 0;
    }
    

    運行結果:
    class
    分析:
    按&a,ptr,&a順序輸出的地址都不變,即說明處理的一直都是常量區的那塊內存。當強行改變常量屬性,對內存進行寫操作時,再次輸出常量 a 的值,還是原來的 2 ,而不是 3 ,此處說明,這里已經是被編譯器優化了,編譯期進行了值替代。

    與volatile一起使用時,編譯器不會做常量折疊等優化
    volatile不允許編譯器對數據做出假定,必須要重重讀數據,而不是進行優化
    eg:
    int main(){
      volatile const int a = 1;
      printf("change before: %d", a);
      int *ptr = const_cast<int*>(&a);
      *ptr = 4;
      printf("change after: %d", a);
    
      return 0;
    }
    
    

    運行結果
    class
    ii. 運行時常量 -- 如果能確定一個變量,在其生存期之間,一直保持值不變,也可以用const來限定。
    eg:

    int main(){
      const int a = cin.get();//get()取單個字符
      cout <<a;
    
      return 0;
    }
    

    運行結果:
    class
    分析:
    說明可以是運行時的const變量
    iii. const可以用來限定集合,如數組。編譯器在編譯階段,不能把集合放在它的符號表中,而是必須分配內存,表明“不能改變的一塊存儲”。在編譯時期,集合中的值,是不可使用的。
    (所謂分配內存,是指靜態分配空間,是指在編譯時期,就可以計算出其大小的,將這些信息寫到可執行文件一些區,在執行時,不必執行額外的代碼來為其分配內存,而是程序直接將這些數據,與物理地址建立映射關系。如,靜態變量與全局變量)
    eg:

    int main(){
      const int array[3]={0,1,2};
      float temp[array[0]];//此種行為編譯器會報錯
      //因為array數組中的值在編譯時不能使用,是運行時的存儲值
    }
    

    Tips:
    C++中const與C中的const的區別:
    const默認內部連接,作用域僅在本文件,而C中,默認外部連接。

  • constexpr
    constexpr是C++11提出的,目的是讓編譯器在編譯時期判斷表達式是否是常量表達式,若是,則可以在編譯時就進行一些優化工作,提高效率。如常量折疊等;若不是,即報錯。
    i. constexpr修飾變量

    constexpr int a = 1;//相當於const限定的編譯時可確定值的用法
    constexpr int b = cin.get();//編譯器報錯,此為運行時確定的存儲
    

    ii. constexpr修飾函數
    當constexpr修飾的函數返回值用作常量表達式時,如用作數組聲明中的維度,要求該函數中,定義的所有變量均為編譯時可決定的值,且不能進行取地址等復雜操作,並且要求傳入的參數也必須是常量表達式
    若返回結果不用做常量表達式,即權當普通函數使用。
    eg:

    返回值作為常量表達式使用:程序可編譯執行
    
    constexpr int test(int a) {
      int b = 2;//個人猜測當返回值用作常量表達式時,b會當做constexpr變量使用
      //printf("b = %d, &b = %x\n", b, &b);//若注釋去掉,編譯器報錯,constexpr函數無法生成常數表達式
      return b;
    }
    int main() {
      int a = 1;
      int b = 1;
    //int array[test(a+b)];
    //若注釋去掉,編譯器報錯,變量a的值不可用作常量
      int array[test(1)];
    
      return 0;
    }
    
    返回值不做常量表達式使用:
    
    傳參不做要求(在以上程序加test(a+b);進行測試,通過)
    返回值是否為常數表達式不做要求
    
    • 一個constexpr修飾的指針的初始值必須是nullptr或者0,或者是存儲於某個固定地址中的對象(如函數體外定義的變量或函數體內的static變量),且constexpr修飾的是指針,而不是指針指向的對象。(即xxx *const ptr;)


免責聲明!

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



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