C語言 學會使用帶參巨集,提高程式設計基礎(二)

2021-09-14 00:25:58 字數 3344 閱讀 8133

帶參巨集在我們的嵌入式程式設計中使用得非常多,其定義如下:

define 識別符號(引數列表) 字串行
其中引數列表中的引數之間用逗號分隔,字串行中應包含參數列中的引數。在定義帶引數的巨集時,巨集名識別符號與左圓括號之間不允許有空白符,應緊接在一起,否則變成了無引數的巨集定義。

並且,字串行與其每乙個引數必須用括號擴起來,否則該巨集定義可能會產生二義性。下面舉個簡單的例子,定義乙個求平方的巨集函式:

#include

#define square(a) a*a

// 不嚴謹的寫法

intmain

(void

)

輸出結果如下:

res變數的輸出結果為17,與我們期望的res = 49;相差甚遠!這就是因為我們不給字串行中的巨集引數加括號的原因,產生了歧義。程式生成可執行程式之前的預處理過程中把square(x+2)替換成了x+2*x+2,因此當x=5時res的結果為17。我們可以使用命令gcc -e hello.c -o hello.i進行預處理,然後檢視經過預處理得到的檔案hello.i的內容,hello.i裡的內容如下:

hello.i裡的內容與我們上面分析的一致!關於c程式的編譯原理可檢視往期筆記:【本質】你知道c語言編譯的過程嗎?關於windows系統下使用gcc編譯器的方法可參考往期筆記:使用notepad++來開發c程式

以上程式嚴謹的求平方的巨集函式的定義如下:

#include

#define square(a) ((a)*(a))

// 嚴謹的做法

intmain

(void

)

程式輸出結果如下:

可見,這才是我們要的正確結果。

帶參巨集到底有多重要,看看ti的一些官方例程就知道,其把很多演算法使用帶參巨集封裝起來,使用者就可以很方便的使用。

帶參巨集—— clarke變換演算法:

帶參巨集—— pi調節器演算法:

其他的巨集來封裝的演算法:

同樣,st官方韌體庫中也大量使用帶參巨集:

\進行分隔,這也是需要注意的細節。

檢視以上帶參巨集,我們發現帶參巨集似乎與函式似乎長得很像,它們之間有什麼區別和聯絡呢?ti為什麼要使用巨集來對一些演算法進行封裝呢,難道使用函式來封裝不可以嗎?答案是可以的:

ti也說了,使用者可以很方便地把這些演算法巨集轉換成一些函式。換句話說就是你可以使用巨集定義,也可以使用函式。那麼,什麼時候封裝成巨集定義比較好,什麼時候封裝成函式比較好呢?

以下內容參考文章:

下面,先看一下帶參巨集與函式的一些區別,舉個例子,比較兩個數或者表示式大小:

(1)帶參巨集的方式:

#define max(a,b) ((a)>(b)?(a):(b))
(2)函式封裝的方式:

int

max(

int a,

int b)

很顯然,我們不會選擇用函式來完成這個任務,原因有兩個:

(1)首先,函式呼叫會帶來額外的開銷,它需要開闢一片棧空間,記錄返回位址,將形參壓棧,從函式返回還要釋放堆疊。這種開銷不僅會降低**效率,而且**量也會大大增加,而使用巨集定義則在**規模和速度方面都比函式更勝一籌;

(2)其次,函式的引數必須被宣告為一種特定的型別,所以它只能在型別合適的表示式上使用,我們如果要比較兩個浮點型的大小,就不得不再寫乙個專門針對浮點型的比較函式。反之,上面的那個巨集定義可以用於整形、長整形、單浮點型、雙浮點型以及其他任何可以用「>」操作符比較值大小的型別,也就是說,巨集是與型別無關的。

除此之外,巨集與函式的不同點還有:巨集是在預處理階段展開,占用的是編譯時間,函式實在程式執行時呼叫的,占用的是程式執行的時間;巨集引數沒有型別說明,也沒有返回值的概念。

和使用函式相比,使用巨集的不利之處在於每次使用巨集時,乙份巨集定義**的拷貝都會插入到程式中。除非巨集非常短,否則使用巨集會大幅度增加程式的長度。

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

看下面的例子:

#define malloc(n, type)\

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

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

int

*ptr;

ptr =

malloc(5

,int

);

將這巨集展開以後的結果:

ptr =

(int*)

malloc((

5)*sizeof

(int))

;

這個例子是巨集定義的經典應用之一,完成了函式不能完成的功能,但是巨集定義也不能濫用,通常,如果相同的**需要出現在程式的幾個地方,更好的方法是把它實現為乙個函式。

以上就是關於帶參巨集的一些總結,如有錯誤,歡迎指出!

C 語言帶參巨集定義和函式的區別

帶參的巨集和帶參函式很相似,但有本質上的不同,把同一表示式用函式處理與用巨集處理 的結果有可能是不同的。示例 用函式計算平方值。1.include 2.3.int sq int y 6.7.int main 12.return 0 13.執行結果 1 2 1 2 2 4 3 2 9 4 2 16 5...

具備C語言的能力下,快速學會使用AWK為了做些什麼

awk是乙個強大的文字分析工具,相對於grep的查詢,sed的編輯,awk在其對資料分析並生成報告時,顯得尤為強大。簡單來說awk就是把檔案逐行的讀入,以空格為預設分隔符將每行切片,切開的部分再進行各種分析處理。輸入awk的文字首先會被按 行 劃分為很多條 記錄 每一行表示一條記錄,每一行再由分隔符...

c語言的變參使用 可變引數巨集 標準預定義巨集

gcc的預處理提供的可變引數巨集定義真是好用 ifdef debug define dbgprint format,args.fprintf stderr,format,args else define dbgprint format,args.endif 如此定義之後,中就可以用dbgprint了...