C/C++中行內函數與靜態函式
C++中的行內函數與靜態函式
靜態函式
靜態函式的定義
靜態函式又稱為內部函式。在C/C++中,定義的函式預設都是全域性的(相對於多個檔案的源程式)。而在函式的前面加上static關鍵字可以改變函式的作用域,即將函式的作用域限定在含有此函式的定義所在的檔案,在其他檔案中不可以使用此函式。
static void fun() {
printf("this is in the static function\n");
}
靜態函式的作用
靜態函式有兩個作用:
- 起隱藏作用,靜態函式只能在本檔案中被訪問,而不能被除此檔案外的其他檔案所使用。
- 使用靜態函式可以在其他檔案中定義同名的函式,而不用考慮會出現名字衝突或者衝定義的錯誤。
靜態函式的記憶體分配
static只會改變(限制)函式的作用域,而不會像靜態變數那樣改變變數的儲存位置。static的函式和普通函式的記憶體儲存區域以及記憶體分配方式是相同的。
行內函數(GCC)
行內函數的定義
GCC中的inline函式可以相當於在一個普通的全域性函式加上inline屬性。inline關鍵字僅僅是建議編譯器在編譯的時候做內聯展開處理,而不是強制在gcc編譯器中,如果吧編譯選項設定為負無窮,即使是inline函式也不會被內聯展開,除非設定了強制內聯展開的屬性(attribute((always_inline)))。
static inline
GCC中static inline定義比較容易理解:可以將其看做是在static函式前面加上了inline屬性.這個函式的大部分屬性和static函式一樣,只不過在呼叫這個函式的時候,gcc會在其呼叫處將其彙編程式碼展開編譯而不為這個函式生成獨立的彙編程式碼。除了以下情況外:
(1)函式的地址被使用時,如果通過函式指標對函式進行了間接呼叫的時候,這種情況下就不得不為static inline函式生成獨立的彙編碼,否則它沒有自己的地址
(2)其他一些無法展開的情況,比如函式本身有遞迴呼叫自己的情況。
static inline函式和static函式一樣,其定義的範圍是local的,即可以在同一個程式的不同的檔案中由同名的函式定義。
注意gcc中的static inline函式和C99中的static inline函式的用法是一致的,不用擔心相容問題
重點:
- gcc的static inline相對於static函式來說只是在呼叫時建議編譯器內聯展開;
- gcc不會特意未static inline函式生成獨立的彙編程式碼,除非出現了非生成不可的情況。
- gcc的static inline函式僅能作用於檔案範圍內。
inline
gcc中的inline函式也想對容易理解,相當於在一個普通的全域性函式的前面加上了一個inline關鍵字。在它定義所在的檔案內,它的表現和static inline的表現一致:再能展開的時候被內聯展開編譯。但是為了能夠在檔案外面呼叫它,gcc一定會為它生成一份獨立的彙編程式碼,以便在檔案外部進行呼叫
重點:
- gcc的inline函式相對於普通的extern函式的區別在於,當同一檔案中呼叫的時候inline是建議進行內聯展開,而extern不會
- gcc一定會為inline函式生成一份獨立的彙編程式碼,以便在本檔案之外的其他檔案呼叫,而static inline可能不需要
- C的inline函式是全域性性的:在檔案內可以作為一個行內函數被展開,而在檔案外可以被呼叫
extern inline
一個extern inline 函式只會被內聯進去,而據對不會聲稱獨立的彙編程式碼,即使是通過指標引用或者遞迴呼叫,也不會生成獨立的彙編程式碼。另外extern inline函式允許和外部函式重名,即在一個同名的extern inline函式存在的情況下,再定義一個相同名字的全域性函式,不會產生衝突。
在這個檔案中gcc不會生成foo函式的彙編碼。在func1中的呼叫點①,編譯器會江山市nga面的foo函式的彙編程式碼內聯到func1中的,而在②處,引用了foo的地址。但是編譯器絕對不會為extern inline函式生成獨立的彙編程式碼,所以這時候編譯器將其處理為外部引用,當外部沒有這個函式的時候,會出現未定義的錯誤。
重點:
- gcc絕對不會為extern inline的函式生成獨立的彙編程式碼
- extern inline函式允許和全域性函式重名,可以在檔案範圍內替代外部定義的全域性函式
- extern inline函式的應用比較狹窄,行為奇怪,不建議使用