簡介
宏定義是C語言提供的三種預處理功能的其中一種,這三種預處理包括:宏定義、檔案包含、條件編譯。
宏定義又稱為宏代換、宏替換,簡稱“宏”。
預處理(預編譯)工作也叫做宏展開:将宏名替換為字元串。
掌握”宏”概念的關鍵是“換”。一切以換為前提、做任何事情之前先要換,準确了解之前就要“換”。
即在對相關指令或語句的含義和功能作具體分析之前就要換:
例如:
#define Pi 3.1415926
把程式中出現的Pi全部換成3.1415926
其它的宏也是同理
注:宏是沒有類型檢測的 在使用的時候要注意宏的類型 比如說一個 數字的宏 你不能拿來當成NSString來使用
不帶參數的宏
不帶參數的宏,其實就是做一下簡單替換
比如說:
// 是否模拟器
#define isSimulator NSNotFound != [[[UIDevice currentDevice] model] rangeOfString:@”Simulator”].location
在代碼中出現 isSimulator的地方都會替換成
NSNotFound != [[[UIDevice currentDevice] model] rangeOfString:@”Simulator”].location
這段代碼 其實他的值是一個BOOL類型的
還有
#define PI 3.1415926
出現PI的地方那個都會會變成3.1415926
這個沒什麼要多餘的,直接過了哒 =)
帶參數的宏
宏除了一般的字元串替換,還要做參數代換,這個是Macro Magic裡面最具有魔法的點
簡單參數宏
#define ADD(a,b) a+b
在代碼中出現
int total = ADD(2,3);
編譯的時候就會替換成:int total = 2+3;
這裡面有個坑,要跳過去
比如定義一個宏:#define S(r) r*r
代碼中使用:S(a+b) 這個時候就會替換成 a+b*a+b 發現問題了吧
是以正确的宏應該是這樣的:#define S(r) (r)*(r)
這個注意表達式的優先級别就可以繞過這個坑了。
宏定義Class
這個用法個人感覺比較少見,但是确實很實用,比如定義一個準從相同協定
下面上一個例子看看
#define CreateClass(className)\
@interface className : NSObject\
-(void)sayHello;\
@end\
@implementation className\
-(void)sayHello \
{\
NSLog(@"Hello,%d",__LINE__);\
}\
@end\
CreateClass(ABC)
這樣就定義了一個ABC的類 有木有很神奇?
Block變量弱引用宏
在使用Block的時候 為了防止循環引用 需要變量弱引用 代碼會比較麻煩
有了宏一切變得簡單了 比如:
#define WEAK_REF(obj) \
__weak typeof(obj) weak_##obj = obj; \
注:\ 在宏中是換行的意思,少了它換行會報錯; ##是連接配接符号,将weak與obj這個參數連接配接成一個字元串
使用時:
WEAK_REF(abc);
Block中用:weak_abc即可
__LINE__宏
在Foundation中定義了一個宏叫 __LINE__ 這個宏是告訴你代碼在第幾行
你可以在任何一行代碼列印__LINE__(NSLog(@”%d”,__LINE__))看看 是不是NSLog所在代碼的行數?
這個大家可以想,如果做背景異常判斷的時候把這個代碼行數打出來,那不是很容易定位到問題所在地方?
類似__LINE__這個宏還有 __FILE__ __FUNCTION__
帶參數的例子也講的差不多了,其他的大家發動思維去做吧 =)
條件編譯
條件編譯,也是一個魔法
最常用的就是各種環境 編譯出不同的代碼,不如一個URL 請求的測試環境和正式環境在開發和線上不是同一個,那一個宏 的條件編譯就解決這個問題了
例子:
#ifdef ABC
URL = @”www”;
#else
URL = @”wwww”
#endif
在來一個例子:
NSLog問題,一般線上上上不需要列印出來,那通過宏也是可以控制的
在xxx.pch檔案中加入
#ifdef __OPTIMIZE__
# define NSLog(…) {}
#else
# define NSLog(…) NSLog(__VA_ARGS__)
#endif
出一個release版本的時候NSLog這個宏就沒有任何作用
解釋:
- __OPTIMIZE__ 這個宏在release編譯的時候Xcode會定義
- 把NSLog作為一個宏定義
- __VA_ARGS__ 這個是一個可變參數宏
預處理指令簡介
- #define 定義一個預處理宏
- #undef 取消宏的定義
- #include 包含檔案指令
- #include_next 與#include相似, 但它有着特殊的用途
- #if 編譯預進行中的條件指令, 相當于C文法中的if語句
- #ifdef 判斷某個宏是否被定義, 若已定義, 執行随後的語句
- #ifndef 與#ifdef相反, 判斷某個宏是否未被定義
- #elif 若#if, #ifdef, #ifndef或前面的#elif條件不滿足, 則執行#elif之後的語句, 相當于C文法中的else-if
- #else 與#if, #ifdef, #ifndef對應, 若這些條件不滿足, 則執行#else之後的語句, 相當于C文法中的else
- #endif #if, #ifdef, #ifndef這些條件指令的結束标志.
- defined 與#if, #elif配合使用, 判斷某個宏是否被定義
- #line 标志該語句所在的行号
- # 将宏參數替代為以參數值為内容的字元竄常量
- ## 将兩個相鄰的标記(token)連接配接為一個單獨的标記
- #pragma 說明編譯器資訊
- #warning 顯示編譯警告資訊
- #error 顯示編譯錯誤資訊
好了,講的比較亂,大家能用多少是多少吧