C++:inline與#define的區別

內聯函數inline

  • 概念:

        以inline修飾的函數叫做內聯函數,編譯時C++編譯器會在調用內聯函數的地方展開,沒有函數壓棧的開銷, 從而能夠提升程序運行的效率。

  • 特性:
  1. inline是一種以空間換時間的做法,省去調用函數的開銷。所以代碼很長或者有循環/遞歸的函數不適宜作爲內聯函數。
  2. inline對於編譯器而言只是一個建議,編譯器會自動優化,如果定義爲inline的函數體內有循環/遞歸等 ,編譯器優化時會忽略掉內聯。
  3. inline不建議聲明和定義分離,分離會導致鏈接錯誤。因爲inline被展開,就沒有函數地址了,鏈接就會找不到。
  4. 內聯函數不能是虛函數。(原因:inline是通過編譯器將函數內容替換到函數調用處,是靜態編譯的。而虛函數是動態調用的,在編譯器並不知道需要調用的是父類還是子類的虛函數,所以不能夠inline聲明展開,因此編譯器會忽略
  • 使用:
  1. 在C++中,在類的內部定義了函數體的成員函數默認是內聯函數,不管是否有inline關鍵字。 
  2. 在內聯函數內不允許用循環語句、開關語句和遞歸調用等,且函數體不宜過長,否則作爲普通函數處理。
  3. 內聯函數的定義必須出現在第一次被調用之前。如果在前面聲明爲普通函數,而在調用代碼後面才定義爲一個inline函數,程序可以通過編譯,但該函數沒有實現inline。
  4. 如果一個inline函數會在多個源文件中被用到,那麼必須把它定義在頭文件中。解析:如果內聯函數fun()定義在某個編譯單元A中,那麼其他編譯單元中調用fun()的地方時,可以編譯通過(此時並沒有展開,結合第三條,此時雖然頭文件聲明瞭該inline函數,但此時調用時,還沒定義,所以作爲普通函數處理)。當鏈接時將無法解析該符號,出現鏈接錯誤。 因爲inline函數是作爲內部連接存在的,只能夠被本模塊訪問
  • 特點: 

        inline函數是函數,有類型,要做類型檢查,因此安全可靠,可以得到一定效率的提升,這個是以增加空間的消耗爲代價


宏替換#define

  • 概念:

        定義預編譯時處理的宏,只是簡單的字符串替換,無類型檢查

  • 特性:
  1. 在宏擴展時,只對宏名做簡單的代換,不做任何計算,也不做任何語法檢查。
  2. 宏由編譯預處理程序處理
  3. 宏定義可出現在程序的任何位置。
  4. 在宏定義中可以使用已定義的宏名。
  • 使用:
  1. 不帶參數的宏定義格式:#define 標識符 字符或字符串
  2. 帶參數的宏定義格式:   #define 宏名(參數表) 使用參數的字符或字符串
  • 特點:

        define無類型,不做檢查就直接替換,因此並不安全,會帶有副作用;宏不能調試,會使得代碼變得龐大。


區別

  1. 內聯函數在編譯時展開,宏在預編譯時由預處理器進行展開。
  2. 內聯函數會檢查參數類型,宏定義不檢查函數參數 ,所以內聯函數更安全。
  3. inline函數是函數,宏不是函數。
  4. 宏在定義時要小心處理宏參數(一般情況是把參數用括弧括起來),否則易出現二義性,而內聯定義不會出現。
  5. 編譯內聯函數可以嵌入到目標代碼,宏只是簡單文本替換。

 

      基於上述區別中的第2點,爲了保證安全性在C++中儘量使用inline代替宏。

 

  1.  

 

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