C語言的宏定義和C++的內聯函數有什麼意義?
像C的#define f1(x) ((x)*(x)),C++的inline int f2(int x) {return x*x}和函數的作用類似,有了函數要它們何用?
宏是預編譯器的輸入,然後宏展開之後的結果會送去編譯器做語法分析。宏與函數等處於不同的級別,操作不同的實體。宏操作的是 token, 可以進行 token的替換和連接等操作,在語法分析之前起作用。而函數是語言中的概念,會在語法樹中創建對應的實體,內聯只是函數的一個屬性。對於問題:有了函數要它們何用?答案是:一:函數並不能完全替代宏,有些宏可以在當前作用域生成一些變數,函數做不到。二:內聯函數只是函數的一種,內聯是給編譯器的提示,告訴它最好把這個函數在被調用處展開,省掉一個函數調用的開銷(壓棧,跳轉,返回)。Happy compiler, happy programmer.我一直覺得我之前看的C++書裡面說「內聯函數是更好的宏」坑了我好幾年……其實壓根就是兩碼事兒,用著有點兒像,但作用機理完全不一樣……
宏是對語言編程,本身高出一個層次,設計好的宏可以幫助完善語言本身不足之處,inline只是彌補了語言一點不足而已。
函數調用是要切換程序上下文,內聯可以把要調用的代碼直接嵌入其中,省去一次函數調用。
題主問
C語言的宏定義和C++的內聯函數有什麼意義?簡要介紹一下這倆的特性吧:
宏是由預處理進行替代,替換所有的相關代碼。
由於宏是直接替換代碼,作用域和使用宏的地方相同。而函數中創建的變數等作用域都在函數內部。可以通過宏輕鬆地定義較短的參數等。宏定義的常量不會出現在記號表內,建議使用const代替。但是宏不能直接訪問對象的私有成員,這個時候需要通過內聯函數達到提高效率的目的。宏是通過標記(token)處理的,一些標記有特殊的功能,如修改編譯時的提示信息等。這些標記的功能大多是函數無法做到的。宏用來寫函數時,相比內聯函數可讀性要差一些,編程過程中要十分注意代碼的結構。尤其在傳遞的參數比較複雜的時候。
內聯函數和宏的代碼展開是有區別的。不能忽視了內聯函數本質上還是個函數。
內聯函數只在函數調用的時候展開。通過編譯器控制。內聯函數的inline關鍵字是給編譯器看的,過長的代碼編譯器會拒絕內聯化!但是宏不會,預處理過程中會強制替換。內聯函數中不要調用其他函數。雖然因為內聯函數能夠輕鬆訪問對象私有成員的特性,經常被使用在類中,但是牆裂不建議將構造函數,析構函數內聯。二者都有一定的使用限制,但是由於其執行效率實在是高,尤其是宏有其函數無法替代的特性,所以編程中這兩個還是不可缺少的。使用時按照規範來就行辣。為了效率考慮。
宏是直接把代碼展開,省去了函數調用。比如下面這段代碼int plus(int a, int b) {
return a + b;
}
int main()
{
int a = 1, b = 2;
int c = plus(a, b);
printf("%d
", c);
}
編譯器執行int c = plus(a, b)的時候,做了下面這些事:
1、把printf這句代碼的地址壓入棧2、把參數a, b壓入棧3、call plus,即調用plus函數4、plus函數計算返回值,把結果存入寄存器5、調用ret(找到之前壓入的地址,返回到那個地方),然後繼續直接printf代碼。可以看出這些過程很浪費,完全沒有必要,所以引入了宏假設把plus改成#define plus(a, b) ((a)+(b))
int c = plus(a, b)被展開為
int c = ((a)+(b))
這時就沒有任何函數調用過程,一次即可做完所有事情,所以效率大大提高。
inline函數是為了代替宏出現的,它們的區別樓上已經解釋得很清楚,就不複述了。相比普通函數,內聯函數效率更高,其主要原因為內聯函數不需要中斷調用,通過複製代碼節省了函數調用的時間。
從內聯函數的實現我們可以看出,其僅僅節省了函數調用的時間,若本身內聯的函數耗時就長,節省這麼一點調用時間並不會有太大的提升,而且函數本身複雜,相應最終可執行文件的大小增量卻比較大,因此內聯函數不應過大,主要用於以下幾種情況:
1)一個函數不斷被重複調用2)函數簡單,不包含for、while、switch等語句。實現時需要注意:
1、關鍵字inline必須與函數定義體放在一起才能使函數成為內聯,僅將inline放在函數聲明前不起任何作用。2、內聯函數應該在頭文件中定義。可以確保在調用函數時所使用的定義是相同的,並保證在調用點該函數的定義對編譯器是可見的。宏與內聯函數的對比:
1、內聯函數相比較於宏而言,內聯函數要做參數類型檢查,從而內聯函數相比宏而言更加安全。2、內聯函數在運行時可調試,而宏定義不可以。個人公眾號:IT小咖坊
新浪博客:IT小咖2016_新浪博客個人郵箱:itxkf2016@163.com宏允許在編譯時指定一些參數。這是函數沒法做到的。除此之外,盡量不要用宏
宏和內聯是啥,作用機理啥的就自己去谷歌吧
宏適合比較小的邏輯,或者一些固定的數字
比如 #define MAGIC_NUM 1000#define min(_a,_b) 之類
一些比較複雜的邏輯,如果使用宏的話,寫起來不舒服,代碼閱讀起來也不爽。這個時候有用內聯函數會更好一點。宏定義可以在編譯預處理階段進行展開,內聯函數也可以在這個階段展開,但是內聯函數會對輸入參數檢查而宏不會。引入內聯函數是為了對一些經常調用的函數進行優化以減少斷點保存和恢復等。
推薦閱讀:
※C++ 類當中為什麼要有private?
※怎麼用好《C++ Primer》(英文版)?
※C++11 移動構造函數問題?
※常量字元串是右值,為什麼沒有調用相應的右值重載函數?
※你有什麼關於Linux下C++並行編程的好書和經驗跟大家分享?
TAG:C |