1. 程式人生 > >行內函數與巨集的簡單說明

行內函數與巨集的簡單說明

1. c 語言中的巨集

c語言使用預處理語句#define來實現巨集定義,例如一個計算平方的巨集:

#define square_mine(x) x*x

需要說明的是,巨集並不是通過傳遞引數實現的,而是通過文字替換來實現。

看下面的例子:

#include <iostream>
#include <Windows.h>

using namespace std;

#define square(x) x*x

int main()
{
    int x = 3;

    cout << "x=" << x << endl;
    cout
<< "x^2 = " << square(x) << endl; cout << "x=" << x << endl; cout << "(x++)^2 = " << square(x++) << endl; cout << "x=" << x << endl; cout << "(x+1)^2 = " << square(x+1) << endl; Sleep(200000); return
0; }

執行結果如下所示:

x=3
x^2 = 9
x=3
(x++)^2 = 9
x=5
(x+1)^2 = 11

這時,我們就發現問題了,似乎與我們想要的結果不同,為什麼呢?主要原因是因為巨集是通過文字替換實現的。也就是說:

  1. square(x)被替換為x*x,這明顯是沒有問題的;
  2. square(x++)被替換為了x++*x++,所以求得的結果變成了(x++)^2 = 9,這是因為先完成x*x,然後兩次x++x++是在所有表示式執行完之後才執行加法的),結果還是9,但需要注意的是,執行此命令之後x=5,而不是我們希望的x=4,這是因為執行了兩次x++;
  3. square(x+1)
    被替換為了x+1*x+1,所以求得的結果變成了(x++)^2 = 11,而不是36,這是因為先完成1*x,然後完成加法,結果變成11;

面對這樣的問題有一個較好的解決辦法,就是在巨集定義的時候加上括號,如:

#define square_mine(x) (x)*(x)

此時的執行結果變為:

x=3
x^2 = 9
x=3
(x++)^2 = 9
x=5
(x+1)^2 = 36
  1. 此時square(x+1)被替換為了(x+1)*(x+1),所以求得的結果為(x++)^2 = 36,結果正確;
  2. 似乎大功告成,但是,請注意,執行完square(x++)x=5,而不是我們希望的x=4,這個問題依舊沒有解決;

2. 為什麼使用巨集

也許很多人問,好好的函式為什麼不用而非要用這樣一不小心就能出錯的巨集呢?完全可以把求平方的巨集寫成下面的函式嘛:

int square(int x)
{
    return x*x;
}

答案是效率。我們知道,程式執行時,作業系統要把這些指令載入到計算機記憶體中,因此每條語句都有特定的地址。

  1. 編譯器在編譯巨集的時候直接把呼叫巨集的部分文字替換,也就相當於你自己寫了進去,所以這些命令是逐條執行的。
  2. 而函式呼叫並非如此。在執行函式呼叫指令時,會跳轉到函式指令對應的記憶體位置,然後執行完之後再跳轉回來。由於這樣的來回跳轉,將導致一定的開銷,所以效率會降低。

對於函式與巨集的執行流程如下所示:

這裡寫圖片描述

3. c++ 行內函數

c++的行內函數似乎是函式與巨集的良好結合,即可以有巨集的效率,又可以有函式方便。

對於行內函數,編譯器在編譯的時候使用響應的函式程式碼替換函式呼叫,對於內聯程式碼,程式無需反覆跳轉到另一個位置執行程式碼。

行內函數的定義如下:

inline int square(int x) { return x*x; }

行內函數與函式執行流程如下:

這裡寫圖片描述

4. 總結

那麼在什麼時候用行內函數呢?

  1. 一個函式被反覆使用時
  2. 一個函式只有簡單的幾行,且不包括for,while,switch語句時

在c語言裡巨集很重要,但在c++裡一般不使用。

行內函數比普通函式快,但是代價是佔用了更多的記憶體,典型的用空間換時間。另外,當執行程式碼的時間較長時,節約的時間相對於程式碼執行的時間來說是很微弱的。

5. 參考

《c++ primer plus》