文章目录
- 1. C 语言
- 1.1 可变宏函数
- 1.2 可变函数
- 2. C++
1. C 语言
c语言中的可变参数写法:
...
1.1 可变宏函数
- 以日志举例,我们写入日志时只需要输入关键信息,行号文件等由宏函数补全
- 这其中,我们需要输入的信息是格式不定的,需要用到可变参数
#include <stdio.h>#define LOG(fmt, ...) printf("[%s:%d]# "fmt, __FILE__, __LINE__, ##__VA_ARGS__);int main()
{// printf("[%s:%d]# %s, %d\n",__FILE__, __LINE__, "something error...", 666);LOG("%s %d\n","something error...", 666);LOG("%s\n","something error...");LOG("something error...\n"); // 如果只传一个fmt,没有可变参数,需要加 ##,意味着当可变参数部分没有的时候,逗号取消return 0;
}
C语言库中的宏
__FILE__
:字符串,记录当前文件名__LINE__
:整型,记录当前行数__VA_ARGS__
:可变参数
1.2 可变函数
va_list
类型,可以定义指向函数参数的指针
va_start
函数:第一个参数是指针,该函数可以让指针指向第二个参数后的第一个可变参数
va_arg
函数:第一个参数是指针,在可变参数范围中找到第二个参数所表示类型的值
va_end
函数:释放 va_list 指针
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>// 实现打印一定个数的一串数字
void numPrint(int cnt, ...)
{va_list p; // 是一个指针,我们需要让他指向函数参数,用于后续打印va_start(p, cnt); // 意思是,让p指向 cnt 参数后的,第一个可变参数的位置// 将可变参数里的内容依次取出来打印for (int i = 0; i < cnt; i++){int num = va_arg(p, int); // 调用一次往后走一次,不需要手动处理printf("param[%d]: %d\n", i, num);}va_end(p); // 销毁指针
}// 实现任何格式的识别和打印
void myprintf(const char *fmt, ...)
{va_list p;va_start(p, fmt);// 有一个接口,是专门做格式解析工作的,我们这里目的是可变参数,格式解析用接口带过char *out;int ret = vasprintf(&out, fmt, p); // 把可变参数内容都以字符串形式,写入retif (ret != -1){printf(out);free(out);}va_end(p);
}int main()
{// 打印数字numPrint(5, 1, 2, 3, 4, 5);numPrint(1, 100);// 打印任意格式myprintf("%s %d %s\n", "这就是", 1, "个测试");myprintf("单参数test\n");return 0;
}
2. C++
#include <iostream>
using namespace std;// 没有可变参数的时候,不能直接用,需要模板特化一下
// 即使我们写的逻辑已经闭环了!但是模板参数他自己就是会推导到最后去!!
// 也就是说,我们在使用可变参数的时候,都要考虑一下没有可变参数的情况
void cppprintf()
{cout << endl;
}template<typename T, typename ...Args> // 不定参的参数包类型
// void cppprintf(T &&v, Args &&...args) // 这里 Args 是参数包的类型,...arg 是不定参数的写法,使用右值引用
void cppprintf(const T &v, Args &&...args)
{cout << v;if((sizeof ...(args)) > 0){cppprintf(forward<Args>(args)...); // forward 完美转发,不会改变左值或者右值的类型}else{cout << endl;}
}int main()
{int a = 111;cppprintf("1个参数");cppprintf("1个参数","2个参数");cppprintf("1个参数","2个参数", a);cppprintf("1个参数","2个参数",333); // T &v,加 const 就能过了,或者改成右值也可以return 0;
}