天天看點

C語言宏

了解c語言的宏,我們首先得了解編譯器編譯c語言程式的過程:

C語言宏

其中預處理器工作有:

(1) 檔案包含:可以把源程式中的#include 擴充為檔案正文,即把包含的.h檔案找到并展開到#include 所在處。

(2) 條件編譯:預處理器根據#if和#ifdef等編譯指令及其後的條件,将源程式中的某部分包含進來或排除在外。

(3) 宏展開:預處理器将源程式檔案中出現的對宏的引用展開成相應的宏定義。

預進行中宏的作用:

(1)友善程式的修正:将某個特定數量在程式中出現的所有執行個體統統加以修改;

(2)提高程式的運作效率:c語言在實作函數調用時會帶來重大系統開銷,宏可以實作一種這樣的程式塊:它看上去像函數,但卻沒有函數調用的開銷。

宏有有兩種定義格式:

(1) 簡單的宏定義:#define <宏名> <字元串>                                  //對應宏作用1

#define pi 3.14

(2) 帶參數的宏定義:#define <宏名> (<參數表>) <宏體>                //對應宏作用2

宏應該注意的地方:

(1)不能忽視宏定義中的空格:

  例子:下面宏定義中 f 是否帶了一個參數?

 答案兩種:f(x) = ((x) - 1) 或者 f=(x)  ((x)-1)

在上述定義中f = (x)  ((x) - 1)是正确的(雖然無法使用),因為 f 和後面的(x)之間多了一個空格。f (3) = 2;

是以在定義宏的時候,要嚴格的注重空格的使用,一般來講帶參數的宏,其參數清單與宏名要相連。

(很有趣:定義#define f(x) ((x) - 1), 調用f(3) = f (3) = 2)

(2)宏不是函數,需注重括号的使用:

例子:

對abs(a-b)求值,宏被展開為:a-b >0 ? a-b : -a-b

例子中的-a-b相當于(-a)-b,而不是我們期望的-(a-b);是以,在定義宏的時候我們最好把每個參數都用括号括起來,整個表達式也括起來。

(3)宏不是類型定義:

看下面代碼:

我們隻需要改動一行代碼,就可以改變a,b,c的類型,宏的這種用法有一個有點:可移植性,得到了所有c編譯器的支援,但是,我們最好還是用typedef來定義:

因為使用宏會帶來意想不到的錯誤,例如:

從定義上看,t1和t2的概念上完全符同,都是指向了foo的指針。但是,當我們試圖使用它們來聲明多個變量時,就會出現問題:

可以看見使用宏擴充并不能得到我們想要的東西。

是以,使用類型定義的時候,我們最好不要使用宏,應該使用typedef。

對于宏的講解結束,讓我們回過頭看看 宏應該注意的地方(1)

對于表達式 (x) ((x) -1) 是否能夠成為一個合法的c表達式呢?

給出一種合了解:

我們定義:typedef int x;

在這種情況下:(x) ((x) - 1) 等價于 (int) ((int) - 1)

即将-1轉換為int類型兩次!

繼續閱讀