今天討論下C/C++的幾個覺問題。
內聯(inline)函數
提到內嵌函式,先看下面兩個程式,程式的執行結界都是為了得到兩個值相加之和:
//程式1
int add(int x,int y)
{
return x+y;
}
int main(int argc,char* argv[])
{
int a=1,b=2,c;
c=add(a,b); //通過調用函數的形式得到相加結果
return 0;
}
//程式2
int main(int argc,int argv[])
{
int a=1,b=2,c;
c=a+b; //直接計算得到相加結果
return 0;
}
上面哪個程式的執行效率更高?
答案是“程式2”是c=a+b直接計算得到相加結果,而“程式1”是通過函數調用c=add(a,b)得到相加的結果。“程式2”的直接計算,節省了函數調用、參數傳值、控制權轉移等開銷,執行效率比“程式1”的函數調用要快得多。
然而,實際工作中,可能會更多地採用“程式1”的函數調用方式,因為從功能封裝和重複使用上來說,通常會將一段通用的程式片段進行封裝,以便在其他需要相同功能的地方調用。這就產生了一個矛盾,如果將一段特定功能的代碼封裝成一個函數,就會大大降低程式效率。
為瞭解決這個問題,C++引入了內嵌函式的概念。內嵌函式給出了一種解決方案:如果一個函數被指定為內聯(inline)函數,則它將在調用點上被“內聯”地展開,內嵌函式不是在調用時發生控制轉移,而是在編譯時間將函數體嵌入在調用處。
這意味著,編寫代碼時,可以採用“程式1”的函數調用形式,等到編譯時間,編譯器會把“程式1”方式編譯成“程式2”的方式,這就是內嵌函式的優點所在。唯一要做的就是,在“程式1”中加入關鍵字inline。
//程式3
inline int add(int x,int y) //聲明為內聯(inline)函數
{
return x+y;
}
int main(int argc,char* argv[])
{
int a=1,b=2,c;
c=add(a,b);
return 0;
}
注意:所謂inline函數,只是對C++編譯器的一個建議。C++編譯器可以選擇忽略這個建議,比如對於大於1200行的函數,或者遞迴調用的函數,或者用到遞迴調用的函數,通常C++編譯器都不會編譯成內嵌函式。
extern "C"
時常在C++的代碼之中看到這樣的代碼:
#ifdef _cplusplus
extern "C" {
#endif
//一段代碼
#ifdef _cplusplus
}
#endif
這樣的代碼到底是什麼意思呢?首先,_cplusplus是C++中的自訂宏,那麼定義了這個宏則表示這是一段C++的代碼,也就是說,上面的代碼的含義是:如果這是一段C++的代碼,那麼加入extern "C"{和}處理其中的代碼。
要明白為何使用extern "C",還得從C++中的重載函數入手。在C++中,為了支援重載機制,在編譯產生的彙編碼中,要對函數的名字進行一些處理,加入比如函數的傳回型別等等。而在C中,只是簡單的函數名字而已,不會加入其他的資訊。也就是說:C++和C對產生的函數名字的處理是不一樣的。所以,一句話,加入extern "C"是防止名字改編。
C和C++對函數的處理方式是不同的。extern "C"是使C++能夠調用C寫的庫檔案的一個手段,如果要對編譯器提示使用C的方式來處理函數的話,那麼就要使用extern "C"來說明。