可变参数宏 __VA_ARGS__
简介
一些函数(如printf())接受数量可变的参数. stdvar.h
头文件提供了工具, 让用户自定义带可变参数的函数. C99/C11 也对宏提供了这样的工具.
通过把宏参数列表中最后的参数写成省略号(即 3个点…)来实现这一功能. 这样, 预处理宏__VA_ARGS__
可用在替换部分中, 表示省略号代表什么. 例如, 下面的定义:
1 |
假设稍后调用该宏:
1 | PR("Howdy"); |
展开后的代码是:
1 | printf("Howdy"); |
加强版变参宏: ##__VA_ARGS__
##__VA_ARGS__
宏前面加上##的作用在于, 当可变参数的个数为0时, 这里的##
起到把前面多余的 “,” 去掉的作用, 否则会编译出错. 使用如下:
1 |
如果可变参数被忽略或为空, ## 操作将使预处理器(preprocessor)去除掉它前面的那个逗号.
如果你在宏调用时, 确实提供了一些可变参数, 它会把这些可变参数放到逗号的后面.
1 |
|
输出
1 | i am C++ :112 name:C语言教程 age:18 line:8 - 02:27:52/May 14 2022 |
用途
我们经常会在一些日志模块中使用到可变参数宏, 参考 WYLogger
1 | @interface WYLogger : NSObject |
这样就可以直接定义一个 WYLogWithLevelAndTag
宏, 方便我们加一些日志等级/日志标记到日志中.
在宏定义中 我们分别用到了...
以及 ##__VA_ARGS__
;
还用到了 NS_FORMAT_FUNCTION(6,7)
, 告诉编译器,索引 6 处的参数是一个格式化字符串,而实际参数从索引 7 处开始。
其中还用到了 __FILE__
__LINE__
, 这些是编译器内置的宏:
DATE 当前日期,一个以 “MMM DD YYYY” 格式表示的字符串常量。
TIME 当前时间,一个以 “HH:MM:SS” 格式表示的字符串常量。
FILE 这会包含当前文件名,一个字符串常量。
LINE 这会包含当前行号,一个十进制常量。
STDC 当编译器以 ANSI 标准编译时,则定义为 1;判断该文件是不是标准C程序。
在实现中
1 | - (void)writeLogFile:(const char *)file |
使用的时候就很方便了,
1 | WYLogWithLevelAndTag(WYLogLevelError, @"测试", @"%@ %d 2-1", @"53", 3); |
输出
1 | [level-4][测试][/path/to/WYRootViewController.m -[WYRootViewController viewDidLoad] 46] 53 3 2-1 |