可变参数宏
说起可变参数,我们用的最多的一个方法NSLog(...)就是可变参数了,可变参数意味着参数的个数是不定的,而NSLog作为我们调试时一个重要的工具实在时太废物了,只能打印对应的时间和参数信息,而文件名,行数,方法名等重要的信息都没有给出,今天我们就借此来实现一个超级版NSLog宏~~~
#define NSLog(format, ...) do { fprintf(stderr, "<%s : %d> %sn",
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__);
fprintf(stderr, "-------n"); } while (0)
首先看这个宏的定义NSLog(format,...)发现它有...,这就是可变参数,而__VA__ARGS__就是除了format外剩下的所有参数,接下来我们发现使用了一个do{}while(0)循环,说明这个循环只执行一便就回停止,感觉废话啊,我们的目的就是只执行一遍啊,但这样写又是为了进行防御式编程,如果有人这样写的话
if (100 > 99)
NSLog(@"%@",@"Fuck");
就会出现无论如何都会执行后两个打印,出现的问题想必大家也都知道,那我们直接使用{}给扩起来不就行了,实际操作后确实是解决了这个问题,但是再扩展一下,当我们使用了if{} else if{}时又会出现新的问题
if (100 > 99)
NSLog(@"%@",@"Fuck");
else {
}
// 展开后可得
if (100 > 99)
{ fprintf(stderr, "<%s : %d> %sn",
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__);
fprintf(stderr, "-------n");};
else {
}
编译错误,大家也发现了NSLog后面会跟上;,如果我么直接使用了{}后,会在编译时在外面加上;,导致编译错误,而使用了do{} while(0)循环后就不会出现这个问题了
if (100 > 99)
do { fprintf(stderr, "<%s : %d> %sn",
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__);
fprintf(stderr, "-------n");} while(0);
else {
}
到此位置问题解决的差不多了,看一下内部的结构,__FILE__是编译的文件路径,__LINE__是行数,__func__是编译的方法名,下面我们又看见了
(NSLog)((format), ##__VA_ARGS__);
##上面已经看见过了,在这里的作用差不多,也是连接的意思,__VA_ARGS__是剩下的所有参数,使用##连接起来后就时NSLog(format,__VA_ARGS__)了,这就是NSLog的方法了,但是不知道有没有人发现一个细节,如果__VA_ARGS__为空的话,那岂不是成了NSLog(format,)这样肯定会编译报错的,但是苹果的大神们早就想到了解决的方法,如果__VA_ARGS__为空的话,在这里##将会吞掉前面的,,这样一来就不会出问题了。然后我们就可以使用这个强大的NSLog()了。










