1. 程式人生 > >C++基礎--行內函數

C++基礎--行內函數

行內函數

函式的引入可以減少程式的目的碼,實現程式程式碼的共享。但是,函式呼叫也需要一些時間和空間方面的開銷,因為呼叫函式實際上將程式執行流程轉移到被調函式中,被調函式的程式程式碼執行完後,再返回到呼叫的地方。這種呼叫操作要求呼叫前保護現場並記憶執行的地址,返回後恢復現場,並按原來儲存的地址繼續執行。對於較長的函式這種開銷可以忽略不計,但是對於一些函式體程式碼很短,但又被頻繁地呼叫的函式,就不能忽視這種開銷。引入行內函數正是為了解決這個問題,提高程式的執行效率。
  在程式編譯時,編譯器將程式中出現的行內函數的呼叫表示式用行內函數的函式體來進行替換。由於在編譯時將函式體中的程式碼替代到程式中,因此會增加目標程式程式碼量,進而增加空間開銷,而在時間開銷上不象函式呼叫時那麼大,可見它是以目的碼的增加為代價來換取時間的節省。
inline函式

  我們看下面的函式,函式體中只有一行語句:
  double Average(double total, int number)
  {
   return total/number;
  }
  定義這麼簡單的函式有必要嗎?實際上,它還是有一些優點的:第一,它使程式更可讀;第二,它使這段程式碼可以重複使用。但是,它也有缺點:當它被頻繁地呼叫的時候,由於呼叫函式的開銷,會對應用程式的效能有損失。例如,Average在一個迴圈語句中重複呼叫幾千次,會降低程式的執行效率。
  那麼,有辦法避免函式呼叫的開銷嗎?對於上面的函式,我麼可以把它定義為行內函數的形式:
  inline double Average(double total, int number)
  {
   return total/number;
  }

上面的行內函數同它的非行內函數相比,僅僅是多了一個關鍵字inline,它們在功能上並沒有區別:前者也是有兩個形參,一個double型,一個int型,返回值是double型,且兩個形參相除後所得的商作為結果返回。但是,編譯器對這兩個函式的呼叫過程的處理是不同的。對於行內函數的呼叫,編譯器是將其函式體放在呼叫的地方,沒有非行內函數呼叫時的棧記憶體的建立和釋放開銷。但是,所執行的計算是完全相同的。
  使用行內函數時應注意以下幾個問題:
  (1)在一個檔案中定義的行內函數不能在另一個檔案中使用。它們通常放在標頭檔案中共享。
  (2) 行內函數應該簡潔,只有幾個語句,如果語句較多,不適合於定義為行內函數。
  (3) 行內函數體中,不能有迴圈語句、if語句或switch語句,否則,函式定義時即使有inline關鍵字,編譯器也會把該函式作為非行內函數處理。
  (4) 行內函數要在函式被呼叫之前宣告。例如下面的程式碼將行內函數放在函式呼叫之後宣告,不能起到預期的效果。

例5-13

#include <iostream.h>
int increment(int i);
inline increment(int i)
{
 i++;
 return i;
}
void main()
{
 int i=0;
 while(i<3)
 {
  i=increment(i);
  cout<<"i is "<<i<<endl;
 }
}

這段程式的輸出結果為:
i is 1
i is 2
i is 3

  如果我們修改一下程式,將行內函數的定義移到main()之後:
例5-14

#include <iostream.h>
int increment(int i);
void main()
{
 int i=0;
 while(i<3)
 {
  i=increment(i);
  cout<<"i is "<<i<<endl;
 }
}
//行內函數定義放在main()函式之後
inline int increment(int i)
{
 i++;
 return i;
}

  行內函數在呼叫之後才定義,這段程式在編譯的時候編譯器不會直接把它替換到main中。也就是說實際上"increment(int i)"只是作為一個普通函式被呼叫,並不具有行內函數的性質,無法提高執行效率。