1. 程式人生 > >行內函數、模板函式 之於標頭檔案

行內函數、模板函式 之於標頭檔案

本文轉自http://blog.csdn.net/cyphei/article/details/7319826

一、基本說明

C++標準中提到,一個編譯單元[translationunit]是指一個.cpp檔案以及它所include的所有.h檔案,.h檔案裡的程式碼將會被擴充套件到包含它的.cpp檔案裡,然後編譯器編譯該.cpp檔案為一個.obj檔案,後者擁有PE[PortableExecutable,即Windows可執行檔案]檔案格式,並且本身包含的就已經是二進位制碼,但是,不一定能夠執行,因為並不保證其中一定有main函式。當編譯器將一個工程裡的所有.cpp檔案以分離的方式編譯完畢後,再由聯結器(linker)進行連線成為一個.exe檔案。

模板函式

  1. template<typename type>  
  2. type compare(type a,type b)  
  3. {  
  4. return a>b?a:b;  
  5. }  

模板函式為對近似型別的共性操作的提取,然後在編譯期間進行根據型別進行例項化(特化),因為編譯期間能夠檢查函式型別。

行內函數

  1. inline compare(int a,int b)  
  2. {  
  3. return a>b?a:b ;  
  4. }  
inline函式對編譯器而言必須是可見的,以便它能夠在呼叫點內展開該函式。與非inline函式不同的是,inline函式不是一次函式的跳轉,而是指令的展開(從而提高執行效率)。如果行內函數過大,就會導致目標碼過大,增加額外的換頁行為,降低指令快取記憶體裝置的擊中率。

所以一般情況下 define定義常量、typedef定義變數、inline宣告小函式~

二、標頭檔案

1、區別&聯絡

模板函式一般宣告為inline函式,但是不是必須的。一個是呼叫點的函式展開、一個為根據型別對函式的過載。兩個功能沒有必然要黏在的理由。

模板函式是需要例項化的,而inline函式不一定需要例項化(當使用到inline函式指標時,需要例項化)。

2、標頭檔案

模板函式放在標頭檔案是因為編譯器檢查型別,編譯器看得見函式實現才能例項化模板。如果放到函式的模板的宣告和實現分開,那麼將會找不到模板實現從而後面引發連結錯誤(目前的編譯器是如此)

inline函式放在標頭檔案是因為方便統一,如果inline函式的定義和宣告是分開的,而在另外一個檔案中需要呼叫這些inline函式得時候,內聯是無法在這些呼叫函式內展開的(上面得第二個例子),只能呼叫。這樣行內函數在全域性範圍內就失去了作用

三、 轉載

轉載兩篇文章。寫的挺深入,留作備份

zz1

把inline函式定義放在標頭檔案中

http://hi.baidu.com/aihfaobh/blog/item/ffc2450899d105d962d9868c.html

兩個檔案:
main.c中得程式碼如下

#include <stdio.h>
#include "print_inline.h"
int main(int argc, char *argv[])

  
print_inline();
system("PAUSE");   
return 0;
}

print_inline.h檔案中得程式碼:

#include <stdio.h>
inline void print_inline()
{
    printf("This is a inlinefunction\n");      
}
在預處理得時候,會把main.c檔案中得print_inline.h標頭檔案展開,在DEVC下,預處理後的檔案為main.i,(如果想要生成預處理後的檔案,需要在工程屬性裡面,為編譯器制定引數-c-save-temps
)得到如下預處理後得結果(檔案比較長,只取了最後的一部分):

# 3 "main.c" 2
# 1 "print_inline.h" 1
inline void print_inline()
{
    printf("This is a inline function\n");
}
# 4 "main.c" 2

int main(int argc, char *argv[])
{
print_inline();
system("PAUSE");
return 0;
}

很明顯,在print_inline.h標頭檔案中定義得函式print_inline()在main函式中被直接展開了,相當與我們把print_inline()函式的定義放在了main.c中,這樣在編譯的時候,編譯器就可以把print_line()函式直接內聯到main函式中

但是如果我們把print_inline()函式的宣告和定義分開,即把print_inline()函式的定義放到另外一個檔案print_inline.c中,結果就不一樣了,在main.i檔案中得內容變為了
# 3 "main.c" 2
# 1 "print_inline.h" 1
inline void print_inline();
# 4 "main.c" 2
int main(int argc, char *argv[])
{
print_inline();
system("PAUSE");
return 0;
}
這個時候,print_inline()函式將無法在main函式中內聯,我們可以檢視生成得main.s彙編程式碼中包含了如下
程式碼:
LM3:
    call   _print_inline


      其實原理很簡單,就是當用#include包含一個檔案得時候,預處理得時候會直接展開這一個檔案,如果檔案中放有某個函式的定義,事實上就相當於把該函式定義放在了這個包含這個檔案(上面得例子中得print_inline.h)的檔案(main.c)中,這樣就可以在main中將print_inline函式內聯展開
      在很多時候,由於某些函式需要經常被呼叫,為了加快程式的執行速度,經常要用到inline,但是如果inline函式的定義和宣告是分開的,而在另外一個檔案中需要呼叫這些inline函式得時候,內聯是無法在這些呼叫函式內展開的(上面得第二個例子),只能呼叫。這樣行內函數在全域性範圍內就失去了作用。解決的辦法就是把行內函數得定義放在標頭檔案中,當其它檔案要呼叫這些行內函數的時候,只要包含這個標頭檔案就可以了。