C_語法_宏定義define和函數的作用…

要寫好C語言,漂亮的宏定義是非常重要的。宏定義可以幫助我們防止出錯,提高代碼的可移植性和可讀性等。

在軟件開發過程中,經常有一些常用或者通用的功能或者代碼段,這些功能既可以寫成函數,也可以封裝成爲宏定義。那麼究竟是用函數好,還是宏定義好?這就要求我們對二者進行合理的取捨。

我們來看一個例子,比較兩個數或者表達式大小,首先我們把它寫成宏定義:

#define MAX( a, b) ( (a) > (b) (a) : (b) )

其次,把它用函數來實現:

int max( int a, int b)

        {

        return (a > b a : b)

        }

很顯然,我們不會選擇用函數來完成這個任務,原因有兩個:首先,函數調用會帶來額外的開銷,它需要開闢一片棧空間,記錄返回地址,將形參壓棧,從函數返回還要釋放堆棧。這種開銷不僅會降低代碼效率,而且代碼量也會大大增加,而使用宏定義則在代碼規模和速度方面都比函數更勝一籌;其次,函數的參數必須被聲明爲一種特定的類型,所以它只能在類型合適的表達式上使用,我們如果要比較兩個浮點型的大小,就不得不再寫一個專門針對浮點型的比較函數。反之,上面的那個宏定義可以用於整形、長整形、單浮點型、雙浮點型以及其他任何可以用“>”操作符比較值大小的類型,也就是說,宏是與類型無關的。

和使用函數相比,使用宏的不利之處在於每次使用宏時,一份宏定義代碼的拷貝都會插入到程序中。除非宏非常短,否則使用宏會大幅度增加程序的長度。

還有一些任務根本無法用函數實現,但是用宏定義卻很好實現。比如參數類型沒法作爲參數傳遞給函數,但是可以把參數類型傳遞給帶參的宏。

 

看下面的例子:

#define MALLOC(n, type) /

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

利用這個宏,我們就可以爲任何類型分配一段我們指定的空間大小,並返回指向這段空間的指針。我們可以觀察一下這個宏確切的工作過程:

int *ptr;

        ptr = MALLOC ( 5, int );

將這宏展開以後的結果:

ptr = (int *) malloc ( (5) * sizeof(int) );

這個例子是宏定義的經典應用之一,完成了函數不能完成的功能,但是宏定義也不能濫用,通常,如果相同的代碼需要出現在程序的幾個地方,更好的方法是把它實現爲一個函數。

 

下面總結和宏和函數的不同之處,以供大家寫代碼時使用,這段總結摘自《C和指針》一書。

代碼長度

 #define宏:每次使用時,宏代碼都被插入到程序中。除了非常小的宏之外,程序的長度將大幅度增長

  函數:函數代碼只出現於一個地方:每次使用這個函數時,都調用那個地方的同一份代碼

 

執行速度

 #define宏:更快

 函數: 存在函數調用、返回的額外開銷

 

操作符優先級

 #define宏:宏參數的求值是在所有周圍表達式的上下文環境裏,除非它們加上括號,否則鄰近操作符的優先級可能產生不可預料的結果。

 函數:函數參數只在函數調用時求值一次,它的結果值傳遞給函數。表達式的求值結果更容易預測。

 

參數求值

 #define宏:參數用於宏定義時,每次都將重新求值,由於多次求值,具有副作用的參數可能會產生不可預測的結果。

 函數:參數在函數調用前只求值一次,在函數中多次使用參數並不會導致多次求值過程,參數的副作用並不會造成任何特殊問題。

 

參數類型

 #define宏:宏與類型無關,只要參數的操作是合法的,它可以用於任何參數類型。

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

發佈了40 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章