printf 函数经常被用来进行打印。其中 printf 函数就是⼀个不定参函数,在函数内部可以根据格式化字符串中格式化字符分别获取不同的参数进行数据的格式化。
一、不定参宏函数
这里使用了可变参数 __VA_ARGS__ 来表示不定参,且 ##__VA_ARGS__ 语法用于处理可变参数为空的情况。
一个简单的宏定义 LOG,用于格式化输出日志信息。其中包含有不定参,调用该宏相当于调用 printf,fmt 表示参数 fmt,表示格式字符串;宏 __FILE__ 表示对应文件名,宏 __LINE__ 表示对应的行号,这两个都是 stdio.h 头文件中的宏;##__VA_ARGS__ 相当于不定参数 ...,## 是为了处理不带参的情况。
二、C 语言风格的不定参函数
需要引入 stdarg.h 头文件,使用其中的 va_list、va_start、va_arg 和 va_end。
- va_list:是一个类型,用于声明一个变量,用该变量来存储不定参数的信息。
- va_start:用于初始化 va_list,让 va_list 指向不定参数列表的起始位置。可以接受 2 个参数,第一个是 va_list 对象,第二个是用于确定不定参数的起始位置。
- va_arg:在不定参数列表中,从 va_list 指向的参数开始,逐个返回 type 类型的数据,一般需要循环调用 va_arg,在此过程中 va_list 会不断往后走。可以接受 2 个参数,一个是 va_list,一个是要获取的参数的类型。
- va_end:用于清理 va_list 对象,清空可变参数列表,使用结束后就失效了,为了避免野指针的引用,va_end 可以销毁 va_list 指针,确保在使用完不定参以后正确的释放资源。
vasprintf:动态分配内存来存储格式化之后的字符串,可以接受可变参数。strp 分别表示指向 char 指针的指针,用来存储格式化后的字符串地址。fmt 是一个格式化的字符串,包含要打印的文本和格式说明符,ap 表示可变参数列表。
vasprintf 会根据 fmt 字符串和可变参数列表 ap 的内容,动态分配足够的内存来存储格式化后的字符串,并将地址存储在 strp 指针中,如果成功就会返回格式化后的字符串的长度,否则返回 -1。
va_list 只是定义了一个变量来存储,是个空指针。当使用 va_start 以后,会让这个空指针与不定参产生联系,可以理解成空指针指向不定参的变量了,此时也就不是空指针了。接着只需要不断地使用 va_arg 去从 va_list 中取出数据即可,最后使用完之后不要忘记用 va_end 关闭。
三、C++ 风格不定参函数
基本模板:
template<typename ...Args>
void print(Args... args) {}
1、递归获取
- args 参数包作为参数传递给另一个函数时,记得加上 ...,表示这个 args 参数是不定参数包。
- 函数接收 Args... 类型的参数包时,通常可以将参数设置为 && 万能引用,以此减少拷贝的成本。
定义了一个模版函数,第 1 个是类型为 T 的参数,第 2 个是不定参数,它的长度不确定。每一次递归调用的时候,不定参数中的第一个参数就会传入到 v 这个位置,就相当于不定参数的一个参数被消耗掉了。然后接着继续递归,不定参数每递归一次就会少一个参数,直到最后没有参数了。