1、先來幾個常用的:
// 是否高清屏#define isRetina ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 960), [[UIScreen mainScreen] currentMode].size) : NO)// 是否模擬器#define isSimulator (NSNotFound != [[[UIDevice currentDevice] model] rangeOfString:@"Simulator"].location)// 是否iPad#define isPad (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)// 是否iPad#define someThing (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)? ipad: iphone
2、基本的使用:
//定義π值 3.1415926 #define PI 3.1415926 //則在程式用可以如下使用 double i=2*PI*3; //效果相當於 double i=2*3.1415926*3; //預先處理命令可以定義任何符合格式的形式,例如判斷年份是否閏年#define IS_LEAP_YEAR year%4==0&&year%100!=0||year%400==0 //使用時則可以直接 if(IS_LEAP_YEAR) //或者可以定義一個參數 #define IS_LEAP_YEAR(y) y%4==0&&y%100!=0||y%400==0 //使用時則可以直接 int ys=2012; if(IS_LEAP_YEAR(ys)) //通常預先處理程式定義在一行 如果好分行 比如說太長需要換行 需要使用“/”符號 表示還有下一行,多行分列也是如此,例: #Define IS_LEAP_YEAR year%4==0&&year%100!=0/ ||year%400==0 //宏定義參數後邊放一個# 那麼在調用該宏時,預先處理程式將根據宏參數建立C風格的常量字串 例: #define STR(x) # x //將會使得 隨後調用的 NSLOG(STR(Programming in Objective-c./n)); //顯示結果為 Programming in Objective-c./n
3、關於#與##的操作符:
<1>.宏定義中字串化操作符#:
#的功能是將其後面的宏參數進行字串化操作,意思就是對它所應用的宏變數通過替換後在其左右各加上一個雙引號。例如
#define WARN_IF(EXPR)\do {\if (EXPR)\fprintf(stderr, "Warning: " #EXPR "\n");\} while(0)上面代碼中的反斜線\主要用來轉譯分行符號,即屏蔽分行符號。那麼如下的代碼調用:WARN_IF(divider == 0);將被解析為:do {\if (divider == 0)\fprintf(stderr, "Warning: " "divider == 0" "\n");\} while(0);
注意能夠字串化操作的必須是宏參數,不是隨隨便便的某個子串(token)都行的。
<2>.宏定義中的串連符##:
串連符##用來將兩個token串連為一個token,但它不可以位於第一個token之前or最後一個token之後。注意這裡串連的對象只要是token就行,而不一定是宏參數,但是##又必須位於宏定義中才有效,因其為編譯期概念(比較繞)。
#define LINK_MULTIPLE(a, b, c, d) a##_##b##_##c##_##dtypedef struct _record_type LINK_MULTIPLE(name, company, position, salary);/** 上面的代碼將被替換為* typedef struct _record_type name_company_position_salary;*/又如下面的例子:#define PARSER(N) printf("token" #N " = %d\n", token##N)int token64 = 64;如下調用宏:PARSER(64);將被解析為:printf("token" "64" " = %d\n", token64);在obj-c中,如果我有如下定義:#define _X(A, B) (A#B)#define _XX(A, B) _X([NSString stringWithFormat:@"%@_c", A], B)gcc將報錯。正確的寫法為:#define _XX(A, B) _X(([NSString stringWithFormat:@"%@_c", A]), B)
4、再來個宏定義 object-c 單例
#define GTMOBJECT_SINGLETON_BOILERPLATE(_object_name_, _shared_obj_name_)static _object_name_ *z##_shared_obj_name_ = nil; + (_object_name_ *)_shared_obj_name_ { @synchronized(self) { if (z##_shared_obj_name_ == nil) { /* Note that ‘self’ may not be the same as _object_name_ */ /* first assignment done in allocWithZone but we must reassign in case init fails */ z##_shared_obj_name_ = [[self alloc] init]; _GTMDevAssert((z##_shared_obj_name_ != nil), @”didn’t catch singleton allocation”); } } return z##_shared_obj_name_; } + (id)allocWithZone:(NSZone *)zone { @synchronized(self) { if (z##_shared_obj_name_ == nil) { z##_shared_obj_name_ = [super allocWithZone:zone];return z##_shared_obj_name_; } } /* We can’t return the shared instance, because it’s been init’d */_GTMDevAssert(NO, @”use the singleton API, not alloc+init”); return nil; } - (id)retain { return self; } - (NSUInteger)retainCount { return NSUIntegerMax; } - (void)release { } - (id)autorelease { return self; } - (id)copyWithZone:(NSZone *)zone { return self; }
5、條件編譯:
#if !defined(FCDebug) || FCDebug == 0#define FCLOG(...) do {} while (0)#define FCLOGINFO(...) do {} while (0)#define FCLOGERROR(...) do {} while (0) #elif FCDebug == 1#define FCLOG(...) NSLog(__VA_ARGS__)#define FCLOGERROR(...) NSLog(__VA_ARGS__)#define FCLOGINFO(...) do {} while (0) #elif FCDebug > 1#define FCLOG(...) NSLog(__VA_ARGS__)#define FCLOGERROR(...) NSLog(__VA_ARGS__)#define FCLOGINFO(...) NSLog(__VA_ARGS__)#endif
6、參照C語言的預先處理命令簡介 :
#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 顯示編譯錯誤資訊
參考連結:http://www.uml.org.cn/c++/200902104.asp