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