天天看點

C++内聯(inline)函數

我的個人部落格網站

内聯函數要解決什麼問題

函數調用是需要額外開銷的,假如有一些短小簡單的函數被頻繁調用,會大量消耗棧空間。

//判斷閏年
bool isLeapYear(int year){
    return (year%4==0&&year%100!=0)||year%400==0;
}

int leapYearsCount(vector<int>& years){
    int ans = 0;
    for(int i=0;i<years.size();++i){
        if(isLearYear(years[i])) ++ans;
    }
    return ans;
}
           

isLeapYear()這個簡單函數被多次調用,浪費棧空間和時間!

有沒有什麼辦法節約這部分開銷

内聯函數原理

有人會這麼寫代碼

int leapYearsCount(vector<int>& years){
    int ans = 0;
    for(int i=0;i<years.size();++i){
        if(year%4==0&&year%100!=0)||year%400==0) ++ans;
    }
    return ans;
}
           

減少了多次調用函數的開銷,但是破壞了函數的可讀性,簡單的說就是代碼變醜了,代碼會變的不易修改。

為了實作編譯器自動替換函數體,我們可以通過inline關鍵字,将函數聲明為内聯函數。
//判斷閏年
inline bool isLeapYear(int year){
    return (year%4==0&&year%100!=0)||year%400==0;
}

int leapYearsCount(vector<int>& years){
    int ans = 0;
    for(int i=0;i<years.size();++i){
        if(isLearYear(years[i])) ++ans;
    }
    return ans;
}
           

這樣既可以也函數形式在程式裡使用isLeapYear(), 又不用在運作時承擔額外開銷。

内聯函數優缺點1

優點
  1. 它通過避免函數調用所帶來的開銷來提高你程式的運作速度。
  2. 當函數調用發生時,它節省了變量彈棧、壓棧的開銷。
  3. 它避免了一個函數執行完傳回原現場的開銷。
  4. 通過将函數聲明為内聯,你可以把函數定義放在頭檔案内。
缺點:
  1. 因為代碼的擴充,内聯函數增大了可執行程式的體積。
  2. C++内聯函數的展開是中編譯階段,這就意味着如果你的内聯函數發生了改動,那麼就需要重新編譯代碼。
  3. 當你把内聯函數放在頭檔案中時,它将會使你的頭檔案資訊變多,不過頭檔案的使用者不用在意這些。
  4. 有時候内聯函數并不受到青睐,比如在嵌入式系統中,嵌入式系統的存儲限制可能不允許體積很大的可執行程式。

什麼時候函數适合定義為内聯2

  1. 函數盡量的短(<10行)
  2. 函數簡單(不能有複雜語句while,switch等)
  3. 内聯函數不能遞歸調用自己
  4. 虛函數不能内聯

注意:

inline聲明是對編譯器的一種建議,編譯器是否覺得采取你的建議取決于函數是否符合内聯的有利條件。

如果函數體非常大,那麼編譯器将忽略函數的内聯聲明,而将内聯函數作為普通函數處理。

内聯函數和宏定義的差別3

  1. 宏由預處理器在預處理階段展開,内聯函數是由編譯器控制的。
  2. 在編譯的時候,内聯函數直接被嵌入到目标代碼中去,而宏隻是一個簡單的文本替換。
  3. 内聯函數是函數,可以進行諸如類型安全檢查、語句是否正确等編譯功能。宏不是函數,不具有這樣的功能。
  4. 内聯函數在運作時可調試,宏定義不可以。

編譯器預設内聯的情況

在類體内定義的函數會被編譯器自動聲明為内聯函數。

參考

  1. 部落格-C++内聯函數 ↩︎
  2. 菜鳥教程-C++内聯函數 ↩︎
  3. 部落格-宏定義和内聯函數差別 ↩︎

繼續閱讀