Objective-C 宏定义详细介绍

2020-01-18 16:28:19于海丽

可是总有写奇葩的写法会出现,而且看开起来还很有道理的样子~


c = MAX(a++,b); // **我直接展开给你看就得了**
// c = a++ > b ? a++ : b
// c = 3++ > 2 ? 3++ : 2
// c = 4
// a = 5

不管这样写的那个人是有多欠揍,但是毕竟看起来是没有任何问题的,所有我们要处理这样的情况,但是使用我们普通的小括号已经无法解决,我们需要使用赋值扩展({...})相信有朋友已经认出来了这种用法了,我们可以使用这样的方法来计算出一个对象,而不用浪费变量名,可以形成小范围的作用域来计算特殊的值


int a = ({
 int b = 10;
 int c = 20;
 b + c;
})
// a = 30;
int b; // 继续使用b和c当变量名也没有问题
int c;

再回到现在这个问题上,我们该如何改装这个宏来让其适应这个坑爹的写法呢

#define MAX(A,B) ({__typeof(A) __a = (A);__typeof(B) __b = (B); __a > __b ? __a : __b; })

__typeof()就是转换为相同类型的变量值,就完美的解决了这个问题,但是还有一个不怎么会发生的意外,通过上面也可以知道,我们生成了新的变量__a, __b,如何有人使用了__a,__b,就会应为变量名重复而编译错误,如果有人这样用了,你可以拿起你的键盘砸他一脸,原因当然不是__a使你的宏错误了,而是__a到底是什么意思,变量名的重要性不言而喻,除非你和看代码的人有仇,否则请使用有意义的变量名,接下来让我们看一看官方的MAX是如何实现的


#define __NSX_PASTE__(A,B) A##B

#if !defined(MAX)
  #define __NSMAX_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__(__b,L) : __NSX_PASTE__(__a,L); })
  #define MAX(A,B) __NSMAX_IMPL__(A,B,__COUNTER__)
#endif

这是Function框架中的MAX定义,我么来一步一步的解析它,首先看见的是

#define __NSX_PASTE__(A,B) A##B
// 将A和B连接到一块

它的作用是将A和B连接到一块,用来生成一个的字符串,比如A##12就成了A12

接下来我们看到了一个有三个参数的宏定义__NSMAX_IMPL__(A,B,__COUNTER__)


#if !defined(MAX)
  #define __NSMAX_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__(__b,L) : __NSX_PASTE__(__a,L); })
  #define MAX(A,B) __NSMAX_IMPL__(A,B,__COUNTER__)
#endif

我们先来解释__COUNTER__是什么,__COUNTER__是一个预编译宏,它将会在每次编译时加1,这样的话可以保证__NSX_PASTE__(__b,__CONNTER__)生成的变量名不易重复,但是这样还是有那么点危险,就是你要是起变量名叫__a20,那就真的真的没有办法了~