c++之行內函數
行內函數
定義:
C++ 行內函數是通常與類一起使用。如果一個函式是內聯的,那麼在編譯時,編譯器會把該函式的程式碼副本放置在每個呼叫該函式的地方。
以inline修飾的函式叫行內函數。編譯時c++編譯器會在呼叫行內函數的地方展開,沒有函式壓棧的開銷,行內函數提升程式執行的效率。
如果想把一個函式定義為行內函數,則需要在函式名前面放置關鍵字 inline,在呼叫函式之前需要對函式進行定義。如果已定義的函式多於一行,編譯器會忽略 inline 限定符。
在類定義中的定義的函式都是行內函數,即使沒有使用 inline 說明符。
引入行內函數的目的是為了解決程式中函式呼叫的效率問題,程式在編譯器編譯的時候,編譯器將程式中出現的行內函數的呼叫表示式用行內函數的函式體進行替換,而對於其他的函式,都是在執行時候才被替代。這其實就是個空間代價換時間的i節省。所以行內函數一般都是1-5行的小函式。
使用原則:
在使用行內函數時要留神:
1.在行內函數內不允許使用迴圈語句和開關語句;
2.行內函數的定義必須出現在行內函數第一次呼叫之前;
3.類結構中所在的類說明內部定義的函式是行內函數。
特性
① 類的成員函式預設為行內函數
② 以空間換取時間,省去函式棧幀的開銷
③ inline必須函式定義放在一起,才能成為行內函數,僅將inline放在宣告前是不起不作用的。
④ 內部程式碼較短,編譯器會自動優化 當函式體內程式碼很長或有遞迴時,內聯不會展開。
例如:
在debug模式下,對編譯器重新設定後:
inline int Add(int a,int b)
{
int c = a + b;
return c;
}
int main()
{
int ret = 0;
ret=Add(100, 20);
cout << "Add(10,3) is :" << ret;
system("pause");
return 0;
}
轉到反彙編:
可以看到 在上述函式前增加inline關鍵字將其改為行內函數,在編譯期間編譯器會用函式體替換函式的呼叫。
行內函數與巨集
行內函數優缺點:
優點: 當函式體比較小的時候, 內聯該函式可以令目的碼更加高效. 對於存取函式以及其它函式體比較短, 效能關鍵的函式, 鼓勵使用內聯.
缺點: 濫用內聯將導致程式變慢. 內聯可能使目的碼量或增或減, 這取決於行內函數的大小. 內聯非常短小的存取函式通常會減少程式碼大小, 但內聯一個相當大的函式將戲劇性的增加程式碼大小. 現代處理器由於更好的利用了指令快取, 小巧的程式碼往往執行更快。
巨集的優缺點:
(1)、巨集只做簡單的字串替換,函式是引數傳遞,所以必然有引數型別檢查(支援各種型別,而不是隻有字串)。
(2)、巨集不經計算而直接替換引數,函式呼叫則是將引數表示式求值再傳遞給形參。
(3)、巨集在編譯前進行,即先替換再編譯。而函式是編譯後,在執行時才呼叫的。巨集佔編譯時間,而函式佔執行時間。
(4)、巨集引數不佔空間,因為只做字串替換,而函式呼叫時引數傳遞是變數之間的傳遞,形參作為區域性變數佔記憶體空間。
(5)、函式呼叫需要保留現場,然後轉入呼叫函式執行,執行完畢再返回主調函式,這些耗費在巨集中是沒有的。
巨集與行內函數的區別:
使用巨集和行內函數都可以節省在函式呼叫方面的時間和空間開銷。二者都是為了提高效率,但是卻有著顯著的區別:
(1)、在使用時,巨集只做簡單的前處理器符號表(字串)中的簡單替換。而行內函數可以進行引數型別檢查,且具有返回值(也能被強制轉換為可轉換的合適型別)。
(2)、行內函數首先是函式,函式的許多性質都適用於行內函數(如行內函數可以過載)。
(3)、行內函數可以作為某個類的成員函式,這樣可以使用類的保護成員和私有成員。而當一個表示式涉及到類保護成員或私有成員時,巨集就不能實現了(無法將this指標放在合適位置)。