大部分入門教材都很少提到預處理,在此給大家分享一下預處理各指示字的應用。
我們知道,源代碼要編譯成可執行文件,首先就必須經過預處理。而預處理就是把源文件中的指示字進行處理。而指示字(directive)一般放在程序開頭,並以#爲開頭的代碼。當然,指示字也可以出現在程序的任何地方。
來看看指示字之一的#define :宏定義
所謂宏定義,說白了就是把一個表達式或常量定義成一個符號,這個符號可以帶有參數。程序在預處理的時候就把這個符號用等價的代碼替換。當然
舉個例子:
第13行定義100爲A,類似於const的使用,不過兩者有本質的區別。
第14行定義showint(a)爲一個printf的函數,並帶有參數a。
可以看看預處理後的結果:
頭文件被展開,宏定義也被展開。
同時也可以看到,宏定義在預處理時就被處理掉了。而const要等到彙編之後才能處理,也就是說,處理的優先級是先處理宏定義。
下面在看看:
(\反斜槓可用來分割代碼,方便閱讀)
輸出結果是:
並沒有輸出ocean;
這說明宏定義在字符串中是不被處理的。當然,如果把上面例子用“”號隔開ARGTERM,就可以傳遞參數,打印出ocean了。當然,也可以在 參數前 加#號把宏定義字符串化(即把參數換成#ARGTERM)。
另外,用宏定義來定義函數時,既要注意效率的問題,也要注意優先級的問題,後者可能會帶來重大錯誤;
例如:
#define max(A,B) (A>B?A:B)
//這樣寫對嗎?
//錯誤1:沒有考慮到優先級;假如有如下一段代碼:
max((a+b),(c+d));//預處理後會怎麼樣呢?
不難得知:結果爲
a+b>c+d?a+b:c+d;
結合優先級的問題,結果不難知道
再者,並且,參數將會運算兩次,這代表着什麼?
1、運算效率的不成熟,憑空多了1次運算;
2、如果上面的參數是a++,b++呢?那就更加糟糕了;
儘管如此,宏定義還是非常有價值的。例如,<ctype.h>頭文件中定義的函數也是常常通過宏實現的;(引用K&R的《C程序設計》)
宏(macro)既可以是靜態的,也可以是動態可變的。即宏的參數可以是可變個。下面纔是重磅
宏定義如#define P(...) printf(__VA_ARGS__)可以輸入多個參數;
這裏要注意__VA_ARGS__兩邊是用雙下劃線。
預處理後的結果是:
處理成功;
綜上:
宏定義是可帶參數的,可以是固定個,也可以是可變個。可變個時用 ... 來代替,並儲存在__VA_ARGS__之中
宏定義:可以是個常量
也可以是個帶參數的表達式
也可以是個帶可變參數的表達式