宏定義在C語言占有舉足輕重的地位。底層框架自不用說,為了編譯優(yōu)化和方便灸眼,以及跨平臺能力霉囚,宏被大量使用盈罐,可以說底層開發(fā)離開define將寸步難行。使用宏的好處是不言自明票顾,在節(jié)省工作量的同時,代碼可讀性大大增加番刊。
通過本文你將了解到:
- 宏定義入門
- 對象宏
- 函數(shù)宏
- 宏定義變長參數(shù)
入門
宏定義簡單點說就是查找替換民晒,但是如果如此理解,那么只說對了一半磁滚,C中的宏分為兩類,對象宏和函數(shù)宏晒他。
對象宏
對象宏一般用來定義一些常數(shù)津滞,比如:
#define PI 3.14159
define
關鍵字表明即將開始一個宏定義,僅接著PI
是宏的名字,空格之后的數(shù)字是內(nèi)容颖侄。類似這樣#define X A
的宏是比較簡單的孝鹊,會在編譯期間温自,將X替換為A,這個過程稱之為展開。
函數(shù)宏
函數(shù)宏是用得最多的丙者,函數(shù)宏可以節(jié)省大量的工作量。
#define MIN(A, B) A < B ? A : B
int a = MIN(1, 2)营密;
printf("%d", a); => 1
輸出正確械媒,可以打包么?
在實際使用中會出問題么评汰,肯定會出問題纷捞。
int a = 2 * MIN(3, 4);
//=> int a = 2 * 3 < 4 ? 3 : 4;
//=> int a = 6 < 4 ? 3 : 4;
//=> int a = 4;
現(xiàn)在知道原因了,我因為展開后運算符優(yōu)先級的問題被去,乘法先被運算了主儡,修正簡單加個括號就行了
#define MIN(A, B) (A < B ? A : B)
僅僅如此么,如果我們執(zhí)行 MIN(3, 4 < 5 ? 4 : 5)
發(fā)現(xiàn)結(jié)果為4惨缆,展開宏后發(fā)現(xiàn)糜值,展開式時鏈接符號和被展開式中的運算符號優(yōu)先級相同丰捷,導致計算順序發(fā)生變化。所以還得再嚴格點臀玄。
#define MIN(A, B) ((A) < (B) ? (A) : (B))
由上可以知道瓢阴,函數(shù)宏可以簡單的將公式展開,這樣能節(jié)省工作量么健无,如果僅僅如此荣恐,當然不行,不過如果運用好#與##符號就能節(jié)省大量的工作累贤。
#與##的使用
# 會將宏參數(shù)轉(zhuǎn)換為一個字符串,簡單理解就是出現(xiàn)在宏定義中的#
是把跟在后面的參數(shù)轉(zhuǎn)換長一個字符串
#define ERROR_LOG(msg) printf("error:#msg\n")
ERROR_LOG("add") => printf("error:"add"")
## 是一種分割鏈接方式叠穆,它的作用是先分隔,然后進行強制連接
#define TYPE(type, name) type name##_##type##_type
TYPE(int, a) => int a_int_type
如何節(jié)省工作量呢
比如有個數(shù)據(jù)結(jié)構(gòu)體臼膏,對于結(jié)構(gòu)體中的每一種數(shù)據(jù)都一個操作接口硼被,常規(guī)實現(xiàn)方式是每個接口都實現(xiàn)一次,這樣隨著數(shù)據(jù)項的增加渗磅,工作量會直線增加嚷硫,利用函數(shù)宏可以完美解決這個問題。
typede struct
{
int nData1;
int nData2;
int nData3;
...
}TData;
#define DEFADDDATA(name, type) \
void Op##_##name(TData a,type data) \
{ \
a.n##name += data; \
}
DEFADDDATA(Data1, int) 展開后為
void Op_Data1(TData a, int data)
{
a.nData1 += data;
}
按照上面所述始鱼,每增加一個數(shù)據(jù)項仔掸,只需要一次函數(shù)宏語句就可以解決,節(jié)省大量工作量医清。
函數(shù)宏的變長參數(shù)
宏可以像函數(shù)一樣起暮,帶可變參數(shù)。語法如下:
#define debug(format, ...) printf(format, __VA_ARGS__)
debug("A message") => printf("A message",)
展開還有問題会烙,因為字符串后面沒有逗號
解決方法:
#define debug(format, ...) printf(format, ##__VA_ARGS__)
這里负懦,如果可變參數(shù)被忽略或為空,##
操作將使預處理器去除掉它前面的那個逗號柏腻。
總結(jié)
宏定義是一把雙刃劍纸厉,用好了節(jié)省大量工作量,并使代碼結(jié)構(gòu)清晰五嫂,如果不好颗品,跳坑不斷,代碼結(jié)構(gòu)混亂贫导。
人生是在不斷跳坑抛猫,填坑的循環(huán)中成長。加油:⒌啤闺金!