1. 程式人生 > >【C語言】巨集和函式的區別

【C語言】巨集和函式的區別

由之前的巨集的引入我們知道,巨集函式可以完成一些簡單的運算。那是不是巨集函式就可以取代函式呢?巨集函式和函式到底有哪些區別呢?

下面我們來分析他們其中的區別。

1.程式碼長度: 

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

而對於函式,函式程式碼只出現在一個地方,每次使用這個函式時,都呼叫那個地方的同一份程式碼。

2.執行速度: 

函式的呼叫是需要付出一定的時空開銷的,因為系統在呼叫函式時,要保留現場,然後轉入被呼叫函式去執行,函式的呼叫會牽涉到引數的傳遞,壓棧/出棧操作,呼叫完再返回主調函式,此時再恢復現場,所以相對較慢。

這些操作,在巨集中是沒有的。

 巨集會在編譯器在對原始碼進行編譯的時候進行簡單替換,不會進行任何邏輯檢測,即簡單程式碼複製而已,所以執行速度更快。

3.操作符優先順序: 

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

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

4.引數求值:

引數每次用於巨集定義時,他們都將重新求值。由於多次求值,具有副作用的引數可能產生不可預料的結果。

例如:

x + 1,可以執⾏⼏百次,每次獲得結果都是⼀樣的,這個表示式不具有副作⽤。

但是,x ++就有副作⽤:它增加x的值。當這個表示式下⼀次執⾏時,將產⽣⼀個不同的結果。

#define MAX( a, b ) ( (a) > ( b) ? (a ) : (b) )
int main()
{
int x = 5;
int y = 8;
int z = MAX( x++, y++);
printf("x = %d, y = %d, z = %d\n" , x, y, z );
return 0;
}

這⾥較⼩的值計算了⼀次,但是較⼤的值卻計算了兩次。這就是具有副作用的巨集引數。

而函式引數在函式被呼叫前只求值一次,在函式中多次使用引數並不會產生多種求值過程。引數的副作用並不會造成任何特殊問題。

5.引數型別

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

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

例如:

#define MALLOC( n,  type)   ( ( type *) malloc ( (n) * sizeof( type ) ) )
int *pi = MALLOC( 25, int );

上述例子就可以表明巨集與型別無關。

6.記憶體佔用

 巨集的引數是不佔記憶體空間的,因為只是做字串的替換.

而函式呼叫時的引數傳遞則是具體變數之間的資訊傳遞,形參作為函式的區域性變數,顯然是佔用記憶體的.