巨集定義函式 普通函式 內聯函式區別

2021-09-24 23:21:21 字數 2626 閱讀 1212

巨集定義函式

例子:單行:#define max(a, b) ((a) > (b) ? (a):(b))

多行:

#define malloc(n, type) \

((type *) malloc((n)* sizeof(type))

對於第乙個函式,如果用普通函式,該怎樣寫?

int max(int a, int b)

很顯然,我們不會選擇用函式來完成這個任務,原因有兩個:

首先,函式呼叫會帶來額外的開銷,它需要開闢一片棧空間,記錄返回位址,將形參壓棧,從函式返回還要釋放堆疊。這種開銷會降低**效率,而使用巨集定義則在**速度方面比函式更勝一籌;

其次,函式的引數必須被宣告為一種特定的型別,所以它只能在型別合適的表示式上使用,我們如果要比較兩個浮點型的大小,就不得不再寫乙個專門針對浮點型的比較函式。反之,上面的那個巨集定義可以用於整形、長整形、單浮點型、雙浮點型以及其他任何可以用「>」操作符比較值大小的型別,也就是說,巨集是與型別無關的

和使用函式相比,使用巨集的不利之處在於每次使用巨集時,乙份巨集定義**的拷貝都會插入到程式中。除非巨集非常短,否則使用巨集會大幅度增加程式的長度。

還有一些任務根本無法用函式實現,但是用巨集定義卻很好實現。比如引數型別沒法作為引數傳遞給函式,但是可以把引數型別傳遞給帶參的巨集。比如上面的malloc的例子.

總結:屬性#define巨集

函式**長度

每次使用時,巨集**都被插入到程式中。除了非常小的巨集之外,程式的長度將大幅度增長。

函式**只出現於乙個地方:每次使用這個函式時,都呼叫那個地方的同乙份**

執行速度

更快存在函式呼叫、返回的額外開銷

操作符優先順序

巨集引數的求值是在所有周圍表示式的上下文環境裡,除非它們加上括號,否則鄰近操作符的優先順序可能產生不可預料的結果。

函式引數只在函式呼叫時求值一次,它的結果值傳遞給函式。表示式的求值結果更容易**。

引數求值

引數用於巨集定義時,每次都將重新求值,由於多次求值,具有***的引數可能會產生不可**的結果。

引數在函式呼叫前只求值一次,在函式中多次使用引數並不會導致多次求值過程,引數的***並不會造成任何特殊問題。

引數型別

巨集與型別無關,只要引數的操作是合法的,它可以用於任何引數型別。

函式的引數是與型別有關係的,如果引數的型別不同,就需要使用不同的函式,即使它們執行的任務是相同的。

補充: 普通函式的呼叫堆疊情況.

比如:

void p()

void q()

p( ),q( ),r( )在經過編譯器變為彙編後, 都有自己的**位置,比如
0x0000400a p:

*** #phase1

call q

*** #phase2

ret0x0000400b q:

yyy #phase3

call r

yyy #phase4

0x0000400c r:

zzz #phase

zzz #phase

而對應的棧幀呢:
---

p的引數入棧

返回位址1(phase2的位址,即函式q後的一下條語句)

---q的引數入棧

返回位址2(phas4的位址,即函式r後的一下條語句)

---r的引數

---

當r函式呼叫完畢,則r的棧幀出棧,同時將返回位址2pop,返回給rip,這樣就繼續執行一下條語句了.q呼叫完畢也是同理的,所以這就是普通函式的呼叫情況.

很顯然,普通函式呼叫在彙編後,這個函式只有乙份**量,呼叫它就入棧出棧它的位址,造成一定的開銷.而對於巨集定義來說,只是簡單的文字替換,這在預處理時就替換過了,故實際上你可以認為就沒有巨集定義出來的函式,所以當然不會有這樣的開銷.

例子:

inline void p() 

void q()

p是乙個內聯函式,對於q來說編譯後得到的彙編是什麼樣子呢?

q:

*** #phase 1

yyy #phase p1

zzz #phase p2

*** #pahse 2

我們可以發現,q的彙編**中並沒有對p的呼叫(call),而是直接將p的**拷到q中,這樣的好處就是由於沒有call ret,所以就沒有普通函式呼叫帶來的出棧入棧開銷,速度更快,但增加**量,增加記憶體開銷.

那麼內聯函式巨集又有哪些不同?

內聯函式本質上還是乙個函式,只是在呼叫時不必call ret罷了.

注意:內聯是以**膨脹(複製)為代價,僅僅省去了函式呼叫的開銷,從而提高函式的執行效率。如果執行函式**的時間比處理函式呼叫機制的時間長,則節省的時間佔比很小;如果**執行時間很短,則內聯函式就可以節省函式呼叫的時間。

內聯函式 普通函式 巨集定義

對於乙個頻繁使用的短小函式,c用巨集定義,c 用inline實現。一 巨集定義和內聯函式 內聯函式和普通函式的區別 1 巨集定義只是普通的文字替換,巨集定義是沒有型別檢查的,無論對還是錯都是直接替換。所以巨集替換容易出錯,直接替換會產生符號的優先順序的問題會一些意想不到的結果。內聯函式在編譯的時候會...

巨集定義 內聯函式 普通函式的區別

巨集定義和內聯函式的區別 第一 巨集定義時在預處理階段進行 替換,而內聯函式在編譯階段進行 替換。第二 巨集定義沒有型別檢查,而內聯函式有型別檢查。內聯函式和普通函式最大的區別是在內部實現方面上 普通函式在被呼叫時,系統首先要跳躍到該函式的入口位址,執行函式體,執行完成後,再返回到函式呼叫的地方,函...

巨集定義 內聯函式 普通函式的區別

一 巨集定義和內聯函式的區別 1.巨集定義不是函式,但是使用起來像函式。預處理器用複製巨集 的方式代替函式的呼叫,省去了函式壓棧退棧過程,提高了效率。內聯函式本質上是乙個函式,內聯函式一般用於函式體的 比較簡單的函式,不能包含複雜的控制語句,while switch,並且內聯函式本身不能直接呼叫自身...