往期資料 == 菜單欄下有更多資料資源分享 | 數(shù)據(jù)結(jié)構(gòu)與算法 帶參宏實例分享帶參宏在我們的嵌入式編程中使用得非常多,其定義如下: #define 標識符(參數(shù)列表) 字符序列 其中參數(shù)列表中的參數(shù)之間用逗號分隔,字符序列中應(yīng)包含參數(shù)表中的參數(shù)。在定義帶參數(shù)的宏時,宏名標識符與左圓括號之間不允許有空白符,應(yīng)緊接在一起,否則變成了無參數(shù)的宏定義。 并且,字符序列與其每一個參數(shù)必須用括號擴起來,否則該宏定義可能會產(chǎn)生二義性。下面舉個簡單的例子,定義一個求平方的宏函數(shù): #include <stdio.h> 輸出結(jié)果如下: res變量的輸出結(jié)果為17,與我們期望的res = 49;相差甚遠!這就是因為我們不給字符序列中的宏參數(shù)加括號的原因,產(chǎn)生了歧義。程序生成可執(zhí)行程序之前的預(yù)處理過程中把SQUARE(x+2)替換成了x+2*x+2,因此當x=5時res的結(jié)果為17。我們可以使用命令gcc -E hello.c -o hello.i進行預(yù)處理,然后查看經(jīng)過預(yù)處理得到的文件hello.i的內(nèi)容,hello.i里的內(nèi)容如下: hello.i里的內(nèi)容與我們上面分析的一致!關(guān)于C程序的編譯原理可查看往期筆記:【本質(zhì)】你知道C語言編譯的過程嗎?關(guān)于windows系統(tǒng)下使用gcc編譯器的方法可參考往期筆記:使用Notepad++來開發(fā)C程序 以上程序嚴謹?shù)那笃椒降暮旰瘮?shù)的定義如下: #include <stdio.h> 程序輸出結(jié)果如下: 可見,這才是我們要的正確結(jié)果。 帶參宏到底有多重要,看看TI的一些官方例程就知道,其把很多算法使用帶參宏封裝起來,用戶就可以很方便的使用。 帶參宏—— clarke變換算法 帶參宏—— PI調(diào)節(jié)器算法 這些.h文件都使用宏來封裝各種算法 同樣,ST官方固件庫中也大量使用帶參宏: 可見帶參宏定義的重要性!除此之外,通過以上宏定義,可發(fā)現(xiàn)很多宏定義分行時,其行后都加上反斜杠 \ 進行分隔,這也是需要注意的細節(jié)。 帶參宏與函數(shù)的區(qū)別查看以上帶參宏,我們發(fā)現(xiàn)帶參宏似乎與函數(shù)似乎長得很像,它們之間有什么區(qū)別和聯(lián)系呢?TI為什么要使用宏來對一些算法進行封裝呢,難道使用函數(shù)來封裝不可以嗎?答案是可以的: TI也說了,使用者可以很方便地把這些算法宏轉(zhuǎn)換成一些函數(shù)。換句話說就是你可以使用宏定義,也可以使用函數(shù)。那么,什么時候封裝成宏定義比較好,什么時候封裝成函數(shù)比較好呢? 以下內(nèi)容參考文章: http://blog.sina.com.cn/s/blog_861912cd0100tc94.html 下面,先看一下帶參宏與函數(shù)的一些區(qū)別,舉個例子,比較兩個數(shù)或者表達式大?。?/span> (1)帶參宏的方式: #define MAX(a,b) ((a)>(b)?(a):(b)) (2)函數(shù)封裝的方式: int max(int a, int b) 很顯然,我們不會選擇用函數(shù)來完成這個任務(wù),原因有兩個: (1)首先,函數(shù)調(diào)用會帶來額外的開銷,它需要開辟一片棧空間,記錄返回地址,將形參壓棧,從函數(shù)返回還要釋放堆棧。這種開銷不僅會降低代碼效率,而且代碼量也會大大增加,而使用宏定義則在代碼規(guī)模和速度方面都比函數(shù)更勝一籌; (2)其次,函數(shù)的參數(shù)必須被聲明為一種特定的類型,所以它只能在類型合適的表達式上使用,我們?nèi)绻容^兩個浮點型的大小,就不得不再寫一個專門針對浮點型的比較函數(shù)。反之,上面的那個宏定義可以用于整形、長整形、單浮點型、雙浮點型以及其他任何可以用“>”操作符比較值大小的類型,也就是說,宏是與類型無關(guān)的。 除此之外,宏與函數(shù)的不同點還有:宏是在預(yù)處理階段展開,占用的是編譯時間,函數(shù)實在程序運行時調(diào)用的,占用的是程序運行的時間;宏參數(shù)沒有類型說明,也沒有返回值的概念。 和使用函數(shù)相比,使用宏的不利之處在于每次使用宏時,一份宏定義代碼的拷貝都會插入到程序中。除非宏非常短,否則使用宏會大幅度增加程序的長度。 還有一些任務(wù)根本無法用函數(shù)實現(xiàn),但是用宏定義卻很好實現(xiàn)。比如參數(shù)類型沒法作為參數(shù)傳遞給函數(shù),但是可以把參數(shù)類型傳遞給帶參的宏。 看下面的例子: #define MALLOC(n, type)\ 利用這個宏,我們就可以為任何類型分配一段我們指定的空間大小,并返回指向這段空間的指針。我們可以觀察一下這個宏確切的工作過程: int *ptr; 將這宏展開以后的結(jié)果: ptr = (int *)malloc((5) * sizeof(int)); 這個例子是宏定義的經(jīng)典應(yīng)用之一,完成了函數(shù)不能完成的功能,但是宏定義也不能濫用,通常,如果相同的代碼需要出現(xiàn)在程序的幾個地方,更好的方法是把它實現(xiàn)為一個函數(shù)。 以上就是關(guān)于帶參宏的一些總結(jié),如有錯誤,歡迎指出! ps:資料鏈接失效怎么辦? |
|