OC 宏入门
来源:互联网 发布:如何做免费网络推广 编辑:程序博客网 时间:2024/06/05 05:10
宏是什么
宏定义是C语言提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译。宏定义和操作符的区别是:宏定义是替换,不做计算,也不做表达式求解。
宏定义的种类
1. 对象宏: (不带参数)
[0]#define [1]SIZE [2]10
[0]#define 定义宏 undef 取消宏定义
[1] 宏名称, 通常用大写字母
[2] 宏定义的内容,在编译期要替换宏名字的内容
2. 函数宏:(带参数)
#define ADD(x, y) x + y
Demo
#define ADD(x, y) x + y# define SIZE 10- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. int size = SIZE + 10; NSLog(@"size = %d", size); int result = ADD(1, 2); NSLog(@"result = %d", result);}
通过xcrun -sdk iphonesimulator clang -rewrite-objc 后我们可以看一下代码转化后的结果
int size = 10 + 10; NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_032276_mi_0, size); int result = 1 + 2; NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_032276_mi_1, result);
从上面的结果中可以看出。这里编译器只是进行了替换。
宏函数并非平常的函数操作,其本质还是代码块的替换。
看一个交换 a, b 两个值的宏
#define YM_Swap(_a_, _b_) { __typeof__(_a_) _t_ = _a_; (_a_) = (_b_); (_b_) = (_t_); } int left_number = 10; int right_number = 100; YM_Swap(left_number, right_number); NSLog(@"left_number = %d, right_number = %d",left_number, right_number);
转化后的结果:
int left_number = 10; int right_number = 100; { int _t_ = left_number; (left_number) = (right_number); (right_number) = (_t_); }; NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_646835_mi_0,left_number, right_number);
从上面的结果来看,只是代码的替换,而不是作为一个函数去执行。这就是为什么有人疑问为什么宏能把两个数正真交换,而普通的函数只是参数的交换。
int totalNumber = SIZE - ADD(2, 3); NSLog(@"totalNumber = %d", totalNumber); // 5 还是11
rewrite 后的代码
int totalNumber = 10 - 2 + 3; NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_90b4d5_mi_0, totalNumber);
结果是11,还是代码替换。那如果我们想要实现 10 - 5 怎么办?
最简单的方法就是给 2 + 3 放在一个小括号里面了
#define ADD(x, y) (x + y)int totalNumber = SIZE - ADD(2, 3);
rewrite 后的代码
int totalNumber = 10 - (2 + 3); NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_d954c3_mi_0, totalNumber);
当多个宏连接使用时,运算符的级别跟连接符的级别是一样的,并不会先计算出结果然后再连接。只会一一展开
对于需要多行的宏,可以使用 \ 来连接
#define MINA(A,B) __typeof__(A) __a = (A);\ __typeof__(B) __b = (B);\ __a < __b ? __a : __b;
宏的返回值
当需要把宏内容的最后一条语句的执行结果当作返回值时,我们就可以用到clang c 的扩展 ({})
#define YM_TEST(_a_, _b_) _a_ = 100; _b_=200; int a = 10; int b = 20; int res = YM_TEST(a, b); NSLog(@"res = %d", res);
转换后的代码
int a = 10; int b = 20; int res = a = 100; b=200;; NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_602c07_mi_0, res);
输出结果 res = 100
如果想要结果为最后一个表达式的值,
#define YM_TEST(_a_, _b_) ({_a_ = 100; _b_=200;}) int a = 10; int b = 20; int res = YM_TEST(a, b); NSLog(@"res = %d", res);
转换后的代码
int a = 10; int b = 20; int res = ({a = 100; b=200;}); NSLog((NSString *)&__NSConstantStringImpl__var_folders_cg_1qk1vr1577l3c1f6bbdbt5hm0000gn_T_ViewController_f857bd_mi_0, res);
输出结果 res = 200
上面的就是为了举例而举例,实际应用可以参考一下前文提到的
#define YM_Swap(_a_, _b_) { __typeof__(_a_) _t_ = _a_; (_a_) = (_b_); (_b_) = (_t_); }
##
连接连个变量
oc中min宏的定义
#define __NSX_PASTE__(A,B) A##B#define __NSMIN_IMPL__(A,B,L) ({__typeof__(A) __NSX_PASTE__(__a,L) = (A);\__typeof__(B) __NSX_PASTE__(__b,L) = (B);\(__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L);\})#define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)int c = MIN(10, 20);NSLog(@"c= %d",c);
转换后的代码
int c = ({ int __a0 = (10); int __b0 = (20); (__a0 < __b0) ? __a0 : __b0; });
__COUNTER__ 是一个全局的变量, 这里为0我们调用时,实际操作为 min (10, 20, 0)__typeof__(A) __NSX_PASTE__(__a,L) = (A) 转成 int __a0 = 10__a##0 的结果就是__a0,就是简单的连接。
全局的COUNTER 完全避免了名字的重复。
##__VA_ARGS__
处理可变参数
#define DeLog(format, ...) do { \printf("<%s : %d> %s\n", \[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \__LINE__, __func__); \NSLog(format, ##__VA_ARGS__); \} while (0)
在宏中使用 … 定义一个可变参数, 当需要用到这个可变参数时,就要使用 ##VA_ARGS 来解析所有的可变参数。
do {} while(0)是干什么用的, 为什么不直接写成 {}。 说实话其实没什么用,只是让转化后的代码更好看,如果没有 do…while 转换后的代码 { };。 如果有,转换后的代码 do{ } while(0); 只是花括号后面跟一个;不好看而已, 话说回来了,我们又看不到。所以就无所谓了,写成什么都行。而且编译器会把他优化掉,不会影响效率。
- OC 宏入门
- OC---oc基础入门
- OC入门
- OC入门
- OC-入门
- oc入门
- OC 入门语法大全
- OC基本语法入门
- OC入门笔记
- OC入门第一课
- oc语法快速入门
- OC语言入门
- OC入门、面向对象语法
- [转载]UIKit Dynamics入门(OC)
- OC 入门实现登陆验证
- OC -- 宏
- 一 :ios学习笔记 OC入门1
- 黑马程序员 OC------入门语法学习
- POJ2376 Cleaning Shifts(贪心)
- Linux中的系统调用
- makefile 问题备忘
- 大数相减
- [LeetCode] 19. Remove Nth Node From End of List
- OC 宏入门
- 利用元数据编写查询的通用方法
- Java中自写ArrayList容器
- 关于数组方面的大小计算
- 《virtualbox完全学习手册》之 虚拟机也玩多屏显示
- 搭建hibernate
- POJ 3311 Hie with the Pie (状态压缩DP ,TSP问题)
- TensorFlow进阶:CNN对CIFAR10图像分类
- Just a Hook HDU