在預處理時,對程式中所有出現的“宏名”,都用巨集定義中的字串去代換,這稱為“巨集代換”或“宏展開」。巨集定義是由原始程式中的巨集定義命令完成的。巨集代換是由預處理程序自動完成的。若字串是表達式,我們稱之為函數式巨集定義。
我們以下面兩行程式碼為例,展開描述:
函數式巨集定義:#define MAX(a,b) ((a)>(b)? (a):(b))
普通函數:MAX(a,b) { return a>b?a:b;}
( 1)函數式巨集定義的參數沒有型,預處理器只負責做形式上的替換,而不做參數型別檢查,所以傳參時要格外小心。
(2)函數式巨集定義要注意格式,尤其是括號。
若上面的巨集定義函數寫成#define MAX(a,b) (a>b?a:b)省去內層括號,巨集展開後由於運算子優先級,運行結果出錯;若上面的巨集定義式函數省去外層括號,巨集定義為MAX(a,b),則巨集展開就成了(a)>(b)?(a):(b),運算優先權也是錯了。
(3)若函數參數為表達式,則普通函數的呼叫與函數式巨集定義的替換過程是不一樣的。
普通函數呼叫時先求實參表達式的值再傳給形參,如果實參表達式有Side Effect,那麼這些SideEffect只會發生一次。例如MAX( a, b),如果MAX是普通函數,a和b只會增加一次。但如果MAX函數式巨集定義,則要展開成k = (( a)>( b)?( a):( b)),a和b就不一定增加一次還是兩次了。所以若參數是表達式,替換函數式巨集定義時一定要仔細看好。
(4)呼叫真正函數的程式碼和呼叫函數式巨集定義的程式碼編譯產生的指令不同。
如果MAX是個普通函數,那麼它的函數體return a > b ? a : b; 要編譯產生指令,程式碼中出現的每次呼叫也要編譯產生傳參指令和call指令。而如果MAX是函數式巨集定義,這個巨集定義本身倒不必編譯產生指令,但是程式碼中出現的每次呼叫編譯產生的指令都相當於一個函數體,而不是簡單的幾條傳參指令和call指令。所以,使用函數式巨集定義編譯產生的目標檔會比較大。
優勢:
首先,函數呼叫會帶來額外的開銷,它需要開闢一片堆疊空間,記錄回傳位址,將形參壓棧,從函數傳回還要釋放堆疊,這種開銷會降低程式碼效率,而使用巨集定義則在程式碼規模和速度方面比函數更勝一籌;
#其次,函數的參數必須被宣告為特定的類型,所以它只能在類型合適的表達式上使用,我們如果要比較兩個浮點型的大小,就不得不再寫一個專門針對浮點型大小的比較函數,反之,上面的宏定義可以用於整數、長整數、單浮點型、雙浮點型及其他可以用「<」運算子比較值大小的型別,也就是說,巨集與型別無關。
以上是巨集定義函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!