【C】【C++】可变参数、不定参函数的使用

这篇具有很好参考价值的文章主要介绍了【C】【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】【C++】可变参数、不定参函数的使用,C++,C语言,c语言,c++,开发语言

C语言库中的宏

  1. __FILE__:字符串,记录当前文件名
  2. __LINE__:整型,记录当前行数
  3. __VA_ARGS__:可变参数

语句分析:

#define LOG(fmt, ...) printf("[%s:%d]# "fmt, __FILE__, __LINE__, ##__VA_ARGS__);

用户使用LOG宏函数的时候,只需要想 printf 函数一样传入格式和内容就可以了,比如:LOG("%s\n", "message")
printf 函数本应该输出:message
但在我们使用宏函数扩展后可以输出:[文件名称:所在行数]# message
具体是怎么匹配的呢?看看下面的解释:

1. "[%s:%d]# "fmt --> 中间并没有逗号!相当于在 "[文件名称:所在行数]# " 后拼接上用户给出的 fmt 即 "message"

2. __FILE__, __LINE__, 作为我们在宏函数里“绑定”的两个参数,传入给了我们宏函数中设定好的"[%s:%d]# "这两处

3. ##__VA_ARGS__ 根据用于fmt定义来的可变参数,这里需要加 ## 是因为,如果用户不传入可变参数而是直接输出字符/别的格式
	LOG("message")这样的情况,函数检测到没有多余可变参数,就会把宏函数 ## 前面逗号以后的部分省去
	## 意为,用户传入这个参数就加上,没有就省去

1.2 可变函数

#include <stdarg.h>
  • va_list 类型,可以定义指向函数参数的指针

  • va_start() 函数:第一个参数是指针,该函数可以让指针指向第二个参数后的第一个可变参数

  • va_arg() 函数:第一个参数是指针,在可变参数范围中找到第二个参数所表示类型的值

  • va_end() 函数:释放 va_list 指针


有点懵,别着急,下面两个例子一看就清楚了:

🌰1. 实现打印一定个数的一串数字:

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); // 销毁指针
}

int main()
{
    // 打印数字
	numPrint(5, 1, 2, 3, 4, 5);
    numPrint(1, 100);
    
    return 0;
}

输出结果:
【C】【C++】可变参数、不定参函数的使用,C++,C语言,c语言,c++,开发语言


下面这个函数是专门做格式解析工作的,在第二个举例中会用到,本篇文章主要讲解可变函数系列,所以格式解析我们用这个接口就好:

  • vasprintf() 函数:解析格式字符串到指定位置,注意,其中的第一个参数的空间是被这个函数接口 动态开辟 出来的,使用完毕需要用户手动释放
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <stdio.h>

int asprintf(char **strp, const char *fmt, ...); 
int vasprintf(char **strp, const char *fmt, va_list ap); 

参数 strp:

  • 把解析后的字符串存入一个新开辟的地址空间中,并把地址赋给 strp。

参数 fmt:

  • 格式化字符串

参数 ap:

  • 可变函数参数的指针

🌰2. 实现任何格式的识别和打印:

void myprintf(const char *fmt, ...)
{
    va_list p;
    va_start(p, fmt);

    // 接口 vasprintf,是专门做格式解析工作的,我们这里目的是可变参数,格式解析用接口带过
    char *out;
    int ret = vasprintf(&out, fmt, p); // 把可变参数内容都以字符串形式,写入out
    if (ret != -1)
    {
        printf(out);
        free(out);	// 手动释放动态开辟空间
    }
    va_end(p);
}

int main()
{
    // 打印任意格式
    myprintf("%s %d %s\n", "这就是", 1, "个测试");
    myprintf("单参数test\n");

    return 0;
}

输出结果:
【C】【C++】可变参数、不定参函数的使用,C++,C语言,c语言,c++,开发语言


2. C++

C++ 可变参数

  • 模板类型的写法:...Args,… 代表可变参数,Args可以自定义
  • 形参的写法:Args ...args,…代表可变参数,Args是我们定义的类型,args是不定参形参名可以自定义
  • 使用时,…放在后面,代表可变参数展开

在 使用模板+不定参数 的时候,一定需要注意:

  • 没有可变参数的时候,不能直接用,需要模板特化一下
  • 即使我们写的逻辑已经闭环了!但是模板参数他自己就是会推导到最后去!!
  • 也就是说,我们在使用可变参数的时候,都要考虑一下没有可变参数的情况
#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;
}

【C】【C++】可变参数、不定参函数的使用,C++,C语言,c语言,c++,开发语言


🥰如果本文对你有些帮助,欢迎👉 点赞 收藏 关注,你的支持是对作者大大莫大的鼓励!!(✿◡‿◡) 若有差错恳请留言指正~~文章来源地址https://www.toymoban.com/news/detail-706142.html


到了这里,关于【C】【C++】可变参数、不定参函数的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】C++11语法 ~ 可变参数模板

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年02月19日
    浏览(25)
  • C++ 11新特性之可变参数模板

    概述         随着C++ 11标准的发布,C++语言获得了许多强大的新特性,其中一项显著提升灵活性和实用性的创新便是可变参数模板。这一特性极大地扩展了模板在处理不定数量类型或值参数时的能力,为开发者提供了更为强大且灵活的泛型编程工具。 工作机制       

    2024年02月22日
    浏览(30)
  • 【C++】C++11新特性重点:可变参数+lambda

    C++11新特性第二篇重点 文章目录 上一篇的补充 一、可变参数模板 二、lambda函数 总结 上一篇我们重点讲解了右值引用+移动语义,关于移动构造和移动赋值还有一些需要补充的知识: 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任

    2024年02月09日
    浏览(38)
  • 如何编写一个可变参数函数?如何让所有单片机的所有串口实现printf函数?

    (1)由于真的复习不下去,就想着写一篇博客拉回自己的心思。于是想到了长期有疑惑,但是一直没有进行深入了解的C语言可变参数函数。 (2)本人查阅了一些网上的资料,以及自己的理解写出来了这一片博客。首先再次感谢肯哥的答疑。 (3)借鉴文章: C51单片机中如何

    2024年02月11日
    浏览(33)
  • 【C++杂货铺】C++11新特性——可变参数模板

    C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模板和函数模板中只能含固定数量的模板参数,可变模板参数无疑是一个巨大的改进。然而由于可变模板参数比较抽象,使用起来需要一定的技巧,所以之一块还是比较晦涩的。本

    2024年02月03日
    浏览(29)
  • 【C++进阶】C++11(下)可变参数模板&lambda表达式&包装器

    我们紧接着上一节的讲解来进行 C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象,使用起来需要一定的技巧

    2024年04月11日
    浏览(69)
  • C++11可变参数模板(typename... Args模板参数包或class... Args)(Args... args函数参数包)(递归展开与参数包展开(只支持C++17))

    C++可变参数是指函数的参数个数是可变的,可以在函数定义时不确定参数的个数,需要在函数体内通过特定的语法来处理这些参数。C++11标准引入了新的可变参数模板,使得可变参数的处理更加方便和灵活。在函数定义时,可以使用省略号(…)来表示可变参数,然后通过va_li

    2024年02月08日
    浏览(35)
  • 计算机语言 之【C++】入门级知识讲解(命名空间,C++输入输出,缺省参数,函数重载,引用,内敛函数,auto关键字,for循环,指针空值nullptr)

    三点睡六点起,阎王夸我好身体 不到三点我不睡,太平间里抢C位 目录: 前言: 本片博客是以学习过C语言之后进入C++学习为前提,讲解C++入门级知识,为C++之后的学习做铺垫 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀

    2024年04月11日
    浏览(113)
  • C++(20):普通函数的参数使用auto声明

    C++20进一步解放了对auto的使用,可以在函数的参数中使用auto,auto, auto 并且类型推导的规则与C++11中是一致的 C++(11):auto通过初始化类型推导变量类型_auto如何实现自动推导变量的类型-CSDN博客

    2024年01月22日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包