C/C++中inline/static inline/extern inline的区别及使用
引入內聯函數的目的是為了解決程序中函數調用的效率問題,也是用內聯函數取代帶參宏定義(函數傳參比宏更加方便易用)
???????? 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 {
public:int 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.9;int ret1 = Ceil(a);int ret2 = Ceil(b);std::cout << ret1 << " " << ret2 << " " << std::endl;
}
GitHub: https://github.com/fengbingchun/Messy_Test
總結
以上是生活随笔為你收集整理的C/C++中inline/static inline/extern inline的区别及使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++中#error/assert/st
- 下一篇: C++中static_cast/cons