小問題大思考之C 裡的inline函式

2021-06-18 17:39:38 字數 2550 閱讀 5496

inline,乙個神奇的關鍵字。有了它,你同時就可以獲取函式和巨集的優點。inline定義的函式,比起沒有inline的函式來說,沒有執行函式呼叫所帶來的負擔(對此可參見《c++程式的記憶體布局》),因此它是高效率的;比起巨集來,它具有函式的可預期行為和引數型別檢驗。巨集的行為難於預期,我們看看下面這個巨集定義

#define max(a, b) ( (a) > (b) ? (a) : (b) )

int a = 5, b = 0;

max(++a, b); // a = a + 2

max(++a, b+10); // a = a + 1

如果這樣:

inline int max(int a, int b)

int a = 5, b = 0;

max(++a, b); // a = a + 1

max(++a, b+10); // a = a + 1

一切都很美好!但是會這麼簡單嗎?

c++最初引入inline的原因是不想破壞類的封裝,同時保持高效率。例如:

class stack  // inline函式

};

想訪問stack的成員變數i,想保持stack的封裝,同時還想呼叫時高效率,那麼請inline。

inline對於編譯器而言,意味著「在編譯階段,將呼叫動作以被呼叫函式的本體替換之」。但是它只是一種建議,編譯器可以去做,也可以不去做。從邏輯上來說,編譯器將函式inline的步驟如下:

1、將inline函式體複製到inline函式呼叫點處;

2、為所用inline函式中的區域性變數分配記憶體;

3、將inline函式的的輸入引數和返回值對映到呼叫方法的區域性變數空間中;

4、如果inline函式有多個返回點,將其轉變為inline函式**塊末尾的分支(使用goto)。

int test()

inline int inline_func(int q)

inline後

int test() 

...... // 此處省略**未對b經行修改

int c = b + 1;

......

}

優化後

int test()

上面我們主要說了inline函式的優點,那麼inline函式的缺點有哪些呢?我們來看看:

1、**膨脹。如果inline函式體過大且編譯器還讓它inline成功,那麼你最終的程式會**膨脹,從而造成裝置緩衝命中率低,引起較多的頁面錯誤,讀寫硬碟的次數增多,這樣程式的效能就下降了!建議:inline函式體一般不要超過5行,不包括迴圈,不包括遞迴呼叫。

2、inline函式內部不要有static變數。inline函式的定義幾乎總是放在標頭檔案(.h)裡,這允許多個實現檔案(.cpp)得以引用。我們知道編譯器是分別編譯的,所以這個時候,在多個實現檔案裡就會有多個inline函式的展開,也就是說有個多個static變數,這恐怕不是我們期望的!

3、inline函式無法隨著函式庫公升級而公升級。如果f是函式庫中的乙個inline函式,使用它的使用者會將f函式實體編譯到他們的程式中。一旦函式庫實現者改變f,所有用到f的程式都必須重新編譯。如果f是non-inline的,使用者程式只需重新連線即可。如果函式庫採用的是動態連線,那這一公升級的f函式可以不知不覺的被程式使用。

4、不要獲取inline函式的位址。如果要取得乙個inline函式的位址,編譯器就必須為此函式產生乙個函式實體,無論如何,編譯器無法交出乙個「不存在函式」的指標。注意,有些編譯器可能會使用類的constructors和destructors的函式指標,用以構造和析構乙個class物件的陣列。另外類的constructors和destructors可能簡單,但是其父類的類的constructors和destructors可能是複雜的,所以類的constructors和destructors往往不是inline函式的最佳選擇

5、inline虛函式往往是無效的。虛函式往往是執行時確定的,而inline是在編譯時進行的,所以inline虛函式往往無效。當然如果直接用類的物件來使用虛函式,那麼對有的編譯器而言,也可起到優化的作用。

6、inline函式無法除錯。原因請參見上面編譯器將函式inline的步驟。所以請在專案後期,對程式進行profile後,再決定將那些函式inline化。

參考文獻:

1、《c++語言的設計和演化》2.4 執行時的效率

2、《effective c++》 條款33

3、《提高c++效能的程式設計技術》 第8章 內聯基礎,第9章 內聯-站在效能的角度, 第10章 內聯技巧

4、《c++箴言:理解inline化的介入和排除》

5、《c++ inline 函式》

小問題大思考之C 臨時物件

c 中有這樣一種物件 它在 中看不到,但是確實存在。它就是臨時物件 由編譯器定義的乙個沒有命名的非堆物件 non heap object 為什麼研究臨時物件?主要是為了提高程式的效能以及效率,因為臨時物件的構造與析構對系統效能而言絕不是微小的影響,所以我們應該去了解它們,知道它們如何造成,從而盡可能...

正則裡的一些小問題

通常來講 w我們可以認為是字元類,包括 a za z0 9 但是這個不僅限於英文中,我們應當考慮俄語等語言裡的字元,也是包括在 w中的,正則本質上還是能通過字元編碼集來實現具體操作的,在ascii碼中,如果要匹配,則應當使用 x,而 w其實預設的字元編碼集是unicode 所以應當注意,dz的使用者...

c語言的小問題

在c語言程式設計中要注意乙個小問題,如果你編寫scanf d n printf d n 這個你輸入幾就輸出幾,毫無疑問。但是現在問題來了?如果scanf d n scanf c m 如果你輸入了3和乙個回車鍵,這個時候m的值就是回車鍵。回車鍵回作為乙個字元輸入到m中的。所以當你輸入了數字,後面又要輸...