1. 程式人生 > >內聯函數(五)

內聯函數(五)

C++ inline 內聯函數

或許我們在 C 語言中聽說過內聯函數,但是內聯函數是首先在 C++ 中提出來的,可能現代的 C 編譯器支持內聯函數。

C++ 中的 const 常量可以代替宏常數定義,如:const int A = 3; <==> #define A 3;那麽在 C++ 中是否有解決方案代替宏代碼片段呢?在 C++ 中推薦使用內聯函數替代宏代碼片段,使用 inline 關鍵字聲明內聯函數。內聯函數聲明時 inline 關鍵字必須和函數定義結合在一起,否則編譯器會直接忽略內聯請求。

C++ 編譯器可以將一個函數進行內聯編譯,被 C++ 編譯器內聯編譯的函數叫做內聯函數;C++ 編譯器直接將函數插入函數調用的地方,內聯函數沒有普通函數調用時的額外開銷(壓棧,跳轉,返回等)

;但 C++ 編譯器不一定會滿足函數的內聯請求!

我們以代碼為例來進行分析

#include <stdio.h>

#define FUNC(a, b) ((a) < (b) ? (a) : (b))

inline int func(int a, int b)
{
    return a < b ? a : b;
}

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 3;
    int c = FUNC(++a, b);
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("c = %d\n", c);
    
    return 0;
}

我們在第 3 行定義了宏函數,返回兩個數中的較小值;在第 5 行定義函數返回較小值。我們先用宏函數來返回,在第 14 行比較 ++a 和 b 的值,明顯返回的是 2,那麽最後的值就為 a = 2, b = 3, c = 2;我們來看看結果

技術分享圖片

我們看到的是返回的是 3,仔細看下程序,我們調用的是宏函數,也就是說,這個 ++a 被執行了兩次,所以返回 3 很正常。我們再來把宏函數調用換成函數調用,看看結果

技術分享圖片

我們看到這次和我們分析的是一致的啦,那麽宏函數和函數還是有區別的,宏函數有弊端。

下來我們來講講內聯函數,內聯函數具有普通函數的特征(參數檢查,返回類型等);函數的內聯請求可能會被編譯器拒絕;函數被內聯編譯後,函數體直接擴展到調用的地方;宏代碼片段由預處理器處理,進行簡單的文本替換,沒有任何的編譯過程,因此可能出現副作用

現代 C++ 編譯器能夠進行編譯優化,一些函數即使沒有 inline 聲明,也可能被內聯編譯;一些現代的 C++ 編譯器通過了擴展語法,能夠對函數進行強制內聯,如:g++:__attribute__((always_inline))屬性; MSVC:__forcrinline

下來我們以代碼為例進行分析

#include <stdio.h>


inline 
int add_inline(int n);

int main(int argc, char *argv[])
{
    int r = add_inline(10);

    printf(" r = %d\n", r);

    return 0;
}

inline int add_inline(int n)
{
    int ret = 0;

    for(int i=0; i<n; i++)
    {
        ret += i;
    }

    return ret;
}

我們在 VS2010 中通過斷點調試進到反匯編,看看內聯函數生效了沒。在第 8 行通過調用內聯函數 add_inline,我們看到匯編函數如下

技術分享圖片

我們看到有 call 的調用,證明內聯請求失敗了。還是調用了函數,並沒有在這塊直接把函數體鋪開。這也證明了我們之前所說的不是每一個內聯請求都會得到執行。

在 C++ 中 inline 內聯編譯有這麽幾種條件限制:a> 不能存在任何形式的循環語句;b> 不能存在過多的條件判斷語句;c> 函數體不能過於龐大;d> 不能對函數進行取址操作;e> 函數內聯聲明必須在函數調用語句之前;

通過對內聯函數的學習,總結如下:1、C++ 中可以通過 inline 聲明內聯函數;2、編譯器直接將內聯函數體擴展到函數調用的地方;3、inline 只是一種請求,編譯器不一定允許這種請求;4、內聯函數省去了函數調用時壓棧、跳轉和返回的開銷。


歡迎大家一起來學習 C++ 語言,可以加我QQ:243343083

內聯函數(五)