C語言有許多預處理命令,#define是其預處理命令之一。所有預處理命令以「#」號開頭,如包含命令#include,標準錯誤指令#error,#pragma指令等。#define指令用於宏定義,可以提高原始碼的可讀性,為編程提供方便,一般放在源文件的前面部分。
本文簡要總結#define指令的多種用法及其注意事項。
1、 無參數定義
定義形式如下:
#define 標識符 字符串
無參數宏定義不含參數,常用於常量定義或重新定義數據類型。
1) 常量定義
在編程應用中,對於頻繁使用或具有特殊意義的數字可以採用宏定義,在編譯預處理時,對程序中所有出現的宏名,都用定義的字符串代替。如:#define PI 3.1416,這樣在對源程序作編譯時,將先由預處理程序進行宏代換,即用3.1416去置換所有的宏名PI,然後再進行編譯。切記不要定義成#define PI=3.1416,這是新手常犯錯誤。
如果不再使用已定義過的宏,可以用#undef命令終止該宏定義的作用域。
2) 重新定義數據類型
可以把已有類型定義成一個你想要的新類型名,如#define FT float。編寫源程序時可用FT替代float;在編譯預處理時則將FT全都替換成float。
2、 帶參數定義
C語言允許宏帶有參數,使用帶參數的宏定義可完成函數調用的功能,又能減少系統開銷,提高運行效率。同時也不需要像函數調用那樣保留現場,以便子函數執行結束後能返回繼續執行,同樣在子函數執行完後要恢復調用函數的現場,這都帶來一定的時間開銷。與函數類似,在宏定義中的參數稱為形式參數,在宏調用中的參數稱為實際參數。對帶參數的宏,在調用中,不僅要宏展開,而且要用實參去代換形參。
帶參數宏定義的一般形式為:
#define 宏名(形參表) 字符串
如定義一個求兩個量的乘積的帶參數宏,可以按如下形式定義:
#define MULTIPLY(a,b) ((a)*(b))
假如源程序中有MULTIPLY(5,6),則在編譯預處理時,會用((5)*(6))來替代。
注意,在定義宏時一定要把字符串用括號括起來,並且每一個參數均需括起來,否則程序有可能不會按照你的意圖執行。如果你把宏簡單地定義成了如下形式:
#define MULTIPLY(a,b) a*b
此種定義下,若源程序中有MULTIPLY(2+3,3+3),編譯預處理時不會做任何計算,即絕不會先計算2+3和3+3再替換,而是直接替換。那麼結果將會是2+3*3+3=14,已經不再符合編程的預期結果30。
3、 多行定義
#define可以進行多行定義,用於替代多行語句代碼。定義形式如下:
#define MACRO(參數列表)do{ \
語句1; \
… \
語句n; \
}while(0)
切記,需要在每行的末尾一定要加上「\」,起到換行的作用。
4、 單行定義
#define Conn(x,y) x##y /* x##y表示什麼?表示x連接y */
#define ToChar(x) #@x /* #@x,其實就是給x加上單引號 */
#define ToString(x) #x /* #x是給x加雙引號 */
5、 用#define來處理頭文件嵌套包含問題
由於頭文件包含可以嵌套,那麼c文件有可能包含多次同一個頭文件,就可能出現重複定義的問題的,那麼可以就通過條件編譯開關來避免重複包含,一般頭文件可以做如下定義:
#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件內容
…
#endif
6、 #define特性及使用說明
1) 宏名一般用大寫,且宏定義末尾不加分號;
2) 宏定義通常在文件的最開頭,作用域通常從定義處到文件末尾,也可以用#undef命令提前終止宏定義的作用域;
3) 宏定義不存在類型問題,它的參數也是無類型的,編譯預處理不做語法檢查,不分配內存;
4) 字符串" "中永遠不包含宏;
5) 編程時使用宏可提高程序的通用性和易讀性,減少不一致性,減少輸入錯誤和便於修改。