1. 程式人生 > >C/C++中inline/static inline/extern inline的區別及使用

C/C++中inline/static inline/extern inline的區別及使用

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

 引入行內函數的目的是為了解決程式中函式呼叫的效率問題,也是用行內函數取代帶參巨集定義(函式傳參比巨集更加方便易用)

         inline關鍵字用來定義一個類的行內函數。

 在類體中和類體外定義成員函式是有區別的:在類體中定義的成員函式為內聯(inline)函式,在類體外定義的不是。如果你既希望將函式定義在類體外部,又希望它是行內函數,那麼可以在宣告函式時加 inline 關鍵字.在類體內部定義的函式也可以加 inline 關鍵字,但這是多餘的,因為類體內部定義的函式預設就是行內函數.如果在類體外定義 inline 函式,則必須將類定義和成員函式的定義都放在同一個標頭檔案中(或者寫在同一個原始檔中),否則編譯時無法進行嵌入。

 inline定義的類的行內函數,函式的程式碼被放入符號表中,在使用時直接進行替換,(像巨集一樣展開),沒有了呼叫的開銷,效率也很高。類的行內函數也是一個真正的函式,編譯器在呼叫一個行內函數時,會首先檢查它的引數的型別,保證呼叫正確。然後進行一系列的相關檢查,就像對待任何一個真正的函式一樣。這樣就消除了它的隱患和侷限性。inline可以作為某個類的成員函式,當然就可以在其中使用所在類的保護成員及私有成員。

 inline使用場景:(1)、可以使用inline函式完全取代表達式形式的巨集定義;(2)、行內函數一般只會用在函式內容非常簡單的時候,這是因為,行內函數的程式碼會在任何呼叫它的地方展開,如果函式太複雜,程式碼膨脹帶來的惡果很可能會大於效率的提高帶來的益處。

 在程式編譯時,編譯器將程式中出現的行內函數的呼叫表示式用行內函數的函式體來進行替換。顯然,這種做法不會產生轉去轉回的問題,但是由於在編譯時將函式體中的程式碼被替代到程式中,因此會增加目標程式程式碼量,進而增加空間開銷,而在時間開銷上不像函式呼叫時那麼大,可見它是以目的碼的增加為代價來換取時間的節省。行內函數可減少cpu的系統開銷,並且程式的整體速度將加快,但當行內函數很大時,會有相反的作用,因此一般比較小的函式才使用行內函數.

 有兩種行內函數的宣告方法,一種是在函式前使用inline關鍵字,另一種是在類的內部定義函式的程式碼,這樣的函式將自動轉換為行內函數,而且沒必要將inline放在函式前面。

 內聯是一種對編譯器的請求,下面這些情況會阻止編譯器服從這項請求:如果函式中包含有迴圈,switch或goto語句,遞迴函式,含有static的函式.

 由此可以看出,行內函數和成員函式沒什麼區別,區別就在於怎樣加快函式的執行速度而已。行內函數是浪費空間來節省時間的設定,因為函式的呼叫是很浪費時間的,寫成行內函數可以在每次呼叫時用函式體內容代替函式呼叫,有點類似一個巨集定義。當函式體語句較少,且沒有複雜的迴圈語句,且呼叫次數較多時,就可以用行內函數。

 行內函數從原始碼層看,有函式的結構,而在編譯後,卻不具備函式的性質。編譯時,類似巨集替換,使用函式體替換呼叫處的函式名。一般在程式碼中用inline修飾,但是否能形成行內函數,需要看編譯器對該函式定義的具體處理。

 "static inline" means "we have to have this function, if you use it, but don't inline it, then make a static version of it in this compilation unit". "extern inline" means "I actually _have_ an extern for this function, but if you want to inline it, here's the inline-version".

 static是以前C的用法.目的是讓該關鍵字標識的函式只在本地檔案可見,同一個程式的其它檔案是不可見該函式的.換句話說,就算你其它檔案裡包含了同名同參數表的函式定義的話,也是不會引起函式重複定義的錯誤的.因為static是僅在當前檔案可見。

 static inline,靜態行內函數,它不使用函式呼叫,直接將彙編程式碼插入在呼叫該函式處。

 static inline,可以把它認為是一個static的函式,加上了inline的屬性。static inline函式和static函式一樣,其定義的範圍是local的,即可以在程式內有多個不同的定義(只要不位於同一個檔案內即可)。

 static inline的行內函數,一般情況下不會產生函式本身的程式碼,而是全部被嵌入在被呼叫的地方。如果不加static,則表示該函式有可能會被其他編譯單元所呼叫,所以一定會產生函式本身的程式碼。所以加了static,一般可令可執行檔案變小。Linux核心使用的inline函式大多被定義為static 型別。一個"static inline"函式促使編譯程式嘗試著將其程式碼插入到所有呼叫它的程式中。

 extern inline表示該函式是已宣告過的了.由於函式本身可以宣告多次,所以extern對函式的影響僅僅把函式的隱藏屬性顯式化了. extern 對於非函式的物件是有用的,因為物件宣告時會帶來記憶體的分配,而用 extern就表示該物件已經宣告過了,不用再分配記憶體。

 extern inline函式的應用範圍比較狹窄,一般不建議使用。

 以上內容主要整理自:

 1. http://www.cnblogs.com/pengyingh/articles/2405718.html 

 2. http://stackoverflow.com/questions/216510/extern-inline 

 3. http://wenku.baidu.com/link?url=QVc0SQBmFKDjcz65nQRe5wqsaY-rBp89VAu9iX6aCm2avMORW-IeGf_zYxFYRf4vNi7P-G3eFc7sx_FzzUh2r2EoXEGajf9MWxVm1_sJsVO

 以下為測試程式碼:

 static_inline.h:

#ifndef FBC_MESSY_TEST_STATIC_INLINE_HPP_#define FBC_MESSY_TEST_STATIC_INLINE_HPP_class FastMath {publicint round(float value) { //類體內部定義的函式預設就是行內函數,也可以加 inline 關鍵字,但這是多餘的  return (int)(value + (value >= 0 ? 0.5f : -0.5f)); } inline int floor(float value); // 宣告為行內函數};int FastMath::floor(float value){ int i = round(value); float diff = (float)(value - i); return i - (diff < 0);}static inline int Ceil(float value)int i = (int)(value + (value >= 0 ? 0.5f : -0.5f)); float diff = (float)(i - value); return i + (diff < 0);}void test_static_inline1();void test_static_inline2();#endif // FBC_MESSY_TEST_STATIC_INLINE_HPP_
 static_inline.cpp:

#include "static_inline.hpp"#include <iostream>void test_static_inline1()float a = 4.1, b = 4.9; FastMath math; int ret1 = math.round(a); int ret2 = math.floor(a); int ret3 = math.round(b); int ret4 = math.floor(b); std::cout << ret1 << "   " << ret2 << "    " << ret3 << "    " << ret4 << std::endl;}void test_static_inline2()float a = 4.1, b = 4.9int ret1 = Ceil(a); int ret2 = Ceil(b); std::cout << ret1 << "    " << ret2 << "    " << std::endl;}

  GitHubhttps://github.com/fengbingchun/Messy_Test

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述