Created by 大刘 liuxing8807@126.com
看一些内置的宏(C/C++, OC可用),比如:
__LINE__ 是整数类型;
__FILE__ 宏是字符串类型;
__TIME__ 宏是字符串类型;
__FUNCTION__ 宏是字符串类型;
__DATE__ 宏是字符串类型;
采用#define
定义宏,宏的优劣很明显,但使用宏在某些场景下确实可以起到一些作用;
举其中的一些示例:
宏__FUNCTION__
C语言中获取函数名,一般是__func__,GCC还支持
FUNCTION.同时,
PRETTY_FUNCTION`对函数的打印会带上参数
#include <stdio.h>
void sayHello(char *str) {
printf("%s: hello %s\n", __PRETTY_FUNCTION__, str); // void sayHello(char *): hello daliu
}
int main(int argc, const char * argv[]) {
printf("%s %s %s\r\n",__func__,__FUNCTION__,__PRETTY_FUNCTION__); // main main int main(int, const char **)
sayHello("daliu");
return 0;
}
宏 __COUNTER__
__COUNTER__
也是C的一个宏,它的值从0开始,每次调用就会加1,因为一般可以用来做为UniqueId的一部分.
From Doc:
COUNTER
This macro expands to sequential integral values starting from 0. In conjunction with the ## operator, this provides a convenient means to generate unique identifiers. Care must be taken to ensure that COUNTER is not expanded prior to inclusion of precompiled headers which use it. Otherwise, the precompiled headers will not be used.
上面讲通常搭配连接符##
使用,示例:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#define ZZ_CONCAT(A, B) ZZ_CONCAT2(A, B)
#define ZZ_CONCAT2(A, B) A##B
#define SKILL \
+ (void)ZZ_CONCAT(skill_, __COUNTER__) { \
NSLog(@"%@", NSStringFromSelector(_cmd)); \
}
@interface Person : NSObject
@end
NS_ASSUME_NONNULL_END
#import "Person.h"
#import <objc/runtime.h>
@implementation Person
+ (void)load {
[self printClassMethod:self];
}
// 打印类方法
+ (void)printClassMethod:(Class)cls {
unsigned int methodCount = 0;
// object_getClass(cls) 获取元类对象,类方法存储在元类对象中
Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);
for (unsigned int i = 0; i < methodCount; i++) {
Method method = methods[i];
NSString *methodName = NSStringFromSelector(method_getName(method));
NSLog(@"方法名: %@", methodName);
}
free(methods);
}
SKILL
SKILL
SKILL
SKILL
SKILL
SKILL
@end
程序打印:
方法名: printClassMethod:
方法名: skill_0
方法名: skill_1
方法名: skill_2
方法名: skill_3
方法名: skill_4
方法名: skill_5
方法名: load
宏 __LINE__
__LINE__
表示当前行,是整数类型,示例:
可以在很多场景下使用__LINE__
做一些事情,比如自定义Log并打印出代码的哪一行出现了问题,就可以使用这种方式:
#ifdef DEBUG
#define ZZLog(fmt, ...) NSLog((@"🙍♂️ ZZ log method: %s line: %d " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define ZZLog(fmt, ...)
#endif
需要注意的是,这里的__LINE__
所代指的行号是宏展开的地方,而不是宏定义的地方;而且宏有个特点是它实际上是一行,宏定义中使用了\
只是代码显示的分隔,但实际上仍是一行,因此__LINE__
仍是当前宏展开的那一行,示例:
#import <Foundation/Foundation.h>
#import "Test.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Test test];
}
return 0;
}
1 //
2 // Test.h
3 // TestLine
4 //
5 // Created by daliu.
6 //
7
8 #import <Foundation/Foundation.h>
9
10 NS_ASSUME_NONNULL_BEGIN
11
12 #define PRINT_LINE_METHOD \
13 + (void)printCurrentLine { \
14 NSLog(@"current line is: %d", __LINE__); \
15 }
16
17 @interface Test : NSObject
18
19 + (void)test;
20
21 @end
22
23 NS_ASSUME_NONNULL_END
1 //
2 // Test.m
3 // TestLine
4 //
5 // Created by daliu on 2020/12/5.
6 //
7
8 #import "Test.h"
9
10 @implementation Test
11
12 PRINT_LINE_METHOD
13 // 因为宏展开所在的行是第12行,即在第12行相当于: + (void)printCurrentLine { NSLog(@"current line is: %d", __LINE__); }
14 // 所以打印结果是 current line is: 12
15
16 + (void)test {
17 [self printCurrentLine];
18 }
19
20 @end
网友评论