行內函數與巨集的簡單說明
阿新 • • 發佈:2019-01-08
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
這時,我們就發現問題了,似乎與我們想要的結果不同,為什麼呢?主要原因是因為巨集是通過文字替換實現的
。也就是說:
square(x)
被替換為x*x
,這明顯是沒有問題的;square(x++)
被替換為了x++*x++
,所以求得的結果變成了(x++)^2 = 9
,這是因為先完成x*x
,然後兩次x++
(x++
是在所有表示式執行完之後才執行加法的),結果還是9
,但需要注意的是,執行此命令之後x=5
,而不是我們希望的x=4
,這是因為執行了兩次x++
;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
- 此時
square(x+1)
被替換為了(x+1)*(x+1)
,所以求得的結果為(x++)^2 = 36
,結果正確; - 似乎大功告成,但是,請注意,執行完
square(x++)
後x=5
,而不是我們希望的x=4
,這個問題依舊沒有解決;
2. 為什麼使用巨集
也許很多人問,好好的函式為什麼不用而非要用這樣一不小心就能出錯的巨集呢?完全可以把求平方的巨集寫成下面的函式嘛:
int square(int x)
{
return x*x;
}
答案是效率。我們知道,程式執行時,作業系統要把這些指令載入到計算機記憶體中,因此每條語句都有特定的地址。
- 編譯器在編譯巨集的時候直接把呼叫巨集的部分文字替換,也就相當於你自己寫了進去,所以這些命令是逐條執行的。
- 而函式呼叫並非如此。在執行函式呼叫指令時,會跳轉到函式指令對應的記憶體位置,然後執行完之後再跳轉回來。由於這樣的來回跳轉,將導致一定的開銷,所以效率會降低。
對於函式與巨集的執行流程如下所示:
3. c++ 行內函數
c++的行內函數似乎是函式與巨集的良好結合,即可以有巨集的效率,又可以有函式方便。
對於行內函數,編譯器在編譯的時候使用響應的函式程式碼替換函式呼叫,對於內聯程式碼,程式無需反覆跳轉到另一個位置執行程式碼。
行內函數的定義如下:
inline int square(int x) { return x*x; }
行內函數與函式執行流程如下:
4. 總結
那麼在什麼時候用行內函數呢?
- 一個函式被反覆使用時
- 一個函式只有簡單的幾行,且不包括for,while,switch語句時
在c語言裡巨集很重要,但在c++裡一般不使用。
行內函數比普通函式快,但是代價是佔用了更多的記憶體,典型的用空間換時間。另外,當執行程式碼的時間較長時,節約的時間相對於程式碼執行的時間來說是很微弱的。
5. 參考
《c++ primer plus》