【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.記憶體佔用
巨集的引數是不佔記憶體空間的,因為只是做字串的替換.
而函式呼叫時的引數傳遞則是具體變數之間的資訊傳遞,形參作為函式的區域性變數,顯然是佔用記憶體的.