一、先来几个经常使用的:c#
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 |
二、基本的使用: iphone
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 |
三、关于#与##的操做符:ide
<1>.宏定义中字符串化操做符#:
#的功能是将其后面的宏参数进行字符串化操做,意思就是对它所应用的宏变量经过替换后在其左右各加上一个双引号。例如spa
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)都行的。code
<2>.宏定义中的链接符##:
链接符##用来将两个token链接为一个token,但它不能够位于第一个token以前or最后一个token以后。注意这里链接的对象只要是token就行,而不必定是宏参数,可是##又必须位于宏定义中才有效,因其为编译期概念(比较绕)。orm
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) |
四、再来个宏定义 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 |
} |
五、条件编译:token
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 |
六、参照C语言的预处理命令简介 :ip
#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 显示编译错误信息ci