C中宏分为两类: 对象宏和函数宏
对象宏(object-like macro)
一般用来定义一些常数的, 但却也不是那么简单的查找替换
//This defines PI
#define M_PI 3.14
#define关键字表明即将开始定义一个宏,紧接着的M_PI是宏的名字,空格之后的数字是内容。
类似这样的 #define X A 的宏是比较简单的,在编译时编译器会在语义分析认定是宏后,将X替换为A,这个过程称为宏的展开。
double r =10.0;
double circlePerimeter =2 * M_PI * r;
// => double circlePerimeter = 2 * 3.14 * r;
函数宏(function-like macro)
#define PLUS(x,y) x + y
printf("%d",PLUS(3,2));
// => printf("%d",3 + 2);// => 5
GNU C的赋值扩展 ({...})
类似很多脚本语言,在顺次执行之后,会将最后一次的表达式的赋值作为返回。
int a = ({ int b =1; int c =2; b + c;});// => a is 3
标准MIN宏定义
//GNUC MIN
#define MIN(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
这里定义了三个语句,分别以输入的类型申明了__a和__b,并使用输入为其赋值,接下来做一个简单的条件比较,得到__a和__b中的较小值,并使用赋值扩展将结果作为返回。
这样的实现保证了不改变原来的逻辑,先进行一次赋值,也避免了括号优先级的问题。
#字符串化操作符
#的功能是将其后面的宏参数进行字符串化操作,意思就是对它所应用的宏变量通过替换后在其左右各加上一个双引号。例如
//反斜线\主要用来转译换行符,即屏蔽换行符
#define WARN_IF(EXPR)\
do {\
if (EXPR)\
fprintf(stderr, "Warning: " #EXPR "\n");\
} while(0)
int a=1 , b=1; WARN_IF(a==b); =>> Warning: a==b
注意能够字符串化操作的必须是宏参数,不是随随便便的某个子串(token)都行的。
##连接符
#define LRWeakSelf(type) __weak typeof(type) weak##type = type;
##
是连接的作用, 即当使用上面的宏会把weak
与输入的type
值连接起来如下图:
@#使用
#define LRToast(str) [NSString stringWithFormat:@"%@",str]
//这个宏需要这样写
LRToast(@"温馨提示");
NSLog(@"%@",LRToast(@"温馨提示"));
强调下我只是随便定义一个宏来做示例,以上代码是正常的使用,我们在来看看添加@#是怎么使用的:
#define LRToast(str) [NSString stringWithFormat:@"%@",@#str]
LRToast(温馨提示);
//正常运行,打印不会报错
NSLog(@"%@",LRToast(温馨提示));
@#可以代替@""那么我们以后开发就省事了,不用再添加@""了!