C/C++不定参数的使用

news2024/11/16 9:16:48

文章目录

  • C语言的不定参
  • C++的不定参


C语言的不定参

C语言的不定参数最常见的应用示例就是printf函数,如下,参数列表中的...表示不定参数列表

#include <stdio.h>
int printf(const char *format, ...);

试着模拟实现C语言的printf函数

void myprintf(const char *fmt, ...)
{
    //TODO
}

C语言中,对于...不定参列表,要用va_*系列宏函数操作

#include <stdarg.h>

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
  • va_list

    va_list可以理解为一个指针类型,开始时,通过调用va_start,它会指向不定参列表的第一个参数

  • va_start

    我们知道,C/C++的函数参数通过压栈的方式传入,不定参列表的多个参数也需要压栈。

    在这里插入图片描述

    va_start的作用是使ap指向不定参列表的第一个参数。通过不定参数列表前的最后一个函数参数,找到不定参列表的首元素,并使ap(va_list类型的指针)指向首元素。因此,C函数使用...不定参数,前面至少包含一个其它参数,由它提供不定参数的起始位置。

  • va_arg

    va_arg的作用是在不定参数列表中,从ap指向的参数开始,逐个返回type类型的数据,一般需要循环调用va_arg,在此过程中ap会不断往后走

  • va_end

    ap使用结束后就失效了,为了避免野指针的引用,va_end可以销毁ap指针

  • va_copy

    拷贝src到dest,使得二者指向同一个不定参数列表,src不用再次调用va_start,但要调用va_end

Test Demo:

void myprintf(size_t num, ...)
{
    va_list ap1;
    va_start(ap1, num);
    va_list ap2;
    va_copy(ap2, ap1);
    for (int i = 0; i < num; i++)
    {
        char ch = va_arg(ap1, int);
        std::cout << ch;
    }
    std::cout << std::endl;
    for (int i = 0; i < num; i++)
    {
        char ch = va_arg(ap2, int);
        std::cout << ch;
    }
    std::cout << std::endl;
    va_end(ap1);
    va_end(ap2);
}

int main()
{
    myprintf(3, 'L', 'O', 'L');
    return 0;
}

⭕输出结果

[ckf@VM-8-12-centos 1.before]$ ./vargs 
LOL
LOL

注意:va_arg对于可变参数的处理是有一些规则的,特别是对于小整数类型(如charfloat)。这些类型在传递给va_arg时会被默认转换为intdouble,而不是它们的实际类型。因此,在Test Demo中,对于传入的char类型参数,在调用va_arg时也应该指定type为int,获得返回值后再转换为实际类型char

以下函数可以对不定参数列表进行格式化操作。

#include <stdarg.h>

int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

它们的作用与printf相同,都可以通过参数format,对不定参数进行格式化。区别在于:printf使用不定参...作为格式化的数据,而上面以v开头printf结尾的函数,使用ap指向的不定参数列表作为格式化的数据。除此之外,内部的区别就在于输出的方向了,vprintf将格式化后的字符串输出到stdout,vfprintf输出到指定的文件流,vsprintfvsprintf输出到指定的内存空间str,且后者可以指定输出的字节个数。

Test Demo:

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

    char str[64] = {0};
    int len = vsnprintf(str, sizeof(str), fmt, ap);
    str[len] = 0;
    std::cout << str << std::endl;

    va_end(ap);
}
int main()
{
    myprintf("%s %c %d", "你好", '!', 2024);
    return 0;
}

⭕输出结果

[ckf@VM-8-12-centos 1.before]$ ./vargs 
你好 ! 2024

C++的不定参

💭补充:

  1. args参数包作为参数传递给另一个函数时,记得加...,表示这个args参数是不定参数包
  2. 函数接收Args...类型的参数包时,通常可以将参数设置为&&万能引用,减少拷贝的成本
  3. C++11标准库中,很多构造方法都使用了以不定参数包为参数的条目,方便一些无法缺点参数个数的实例的构造

例如:

  • std::make_shared,由于并不确定构造智能指针指向的对象类型需要传入多少参数,C++11使用了Args不定参数包
    在这里插入图片描述

  • emplace函数,C++11很多容器都重载了这个函数,emplace支持可变参数包,并且用参数包中的参数作为新插入元素构造函数的参数。

    在这里插入图片描述

Test Demo

template <class T>
void myprintfcpp(T val) // 终止函数
{
    std::cout << val;
}

template <class T, class... Args>
void myprintfcpp(T val, Args &&...args)
{
    std::cout << val;
    myprintfcpp(std::forward<Args>(args)...);
}

int main()
{
    myprintfcpp(3, 'L', 'O', 'L');
    std::cout << std::endl;
    return 0;
}

⭕输出结果

[ckf@VM-8-12-centos 1.before]$ ./vargs 
3LOL

END…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1272125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新手村之SQL——分组与子查询

1.GROUP BY GROUP BY 函数就是 SQL 中用来实现分组的函数&#xff0c;其用于结合聚合函数&#xff0c;能根据给定数据列的每个成员对查询结果进行分组统计&#xff0c;最终得到一个分组汇总表。 mysql> SELECT country, COUNT(country) AS teacher_count-> FROM teacher…

Linux系统部署Tale个人博客并发布到公网访问

文章目录 前言1. Tale网站搭建1.1 检查本地环境1.2 部署Tale个人博客系统1.3 启动Tale服务1.4 访问博客地址 2. Linux安装Cpolar内网穿透3. 创建Tale博客公网地址4. 使用公网地址访问Tale 前言 今天给大家带来一款基于 Java 语言的轻量级博客开源项目——Tale&#xff0c;Tale…

敏捷开发实现测试自动化的6个步骤

许多敏捷软件开发中的自动化测试的工作都失败了&#xff0c;或者并没有发挥它们最大的潜力。本文研究分析了自动化测试也许不能满足测试人员和其他利益相关者期望的两个主要原因&#xff0c;然后列举了六个能够避免陷入这些陷阱的步骤。以下是在敏捷环境中成功实现测试自动化的…

Linux系统iptables扩展

目录 一. iptables规则保存 1. 导出规则保存 2. 自动重载规则 ①. 当前用户生效 ②. 全局生效 二. 自定义链 1. 新建自定义链 2. 重命名自定义链 3. 添加自定义链规则 4. 调用自定义链规则 5. 删除自定义链 三. NAT 1. SNAT 2. DNAT 3. 实验 ①. 实验要求 ②. …

设计模式-创建型模式之原型、建造者设计模式

文章目录 七、原型模式八、建造者模式 七、原型模式 原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能。它提供了一种创建对象的最佳方式。 这种模式是实现了一个原型接口&#xff0c;该接口用于创建当前对象的克隆。当直…

C题目12:请写一个函数,判断一个数是否为质数,并在main函数中调用

一.每日小语 人的一切痛苦&#xff0c;本质上都是对自己的无能的愤怒。——王小波 自己思考 判断一个函数是否为质数&#xff0c;这个我在之前练过&#xff0c;我想至少两次&#xff0c;而这一次则是问我如何在main函数中调用&#xff0c;这个概念我不理解&#xff0c;所以我…

软件测试面试最全八股文

请你说一说测试用例的边界 参考回答&#xff1a; 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下&#xff0c;其测试用例来自等价类的边界。 常见的边界值 1)对16-bit 的整数而言 32…

在gitlab上使用server_hooks

文章目录 1. 前置条件2. Git Hook2.1 Git Hook 分为两部分&#xff1a;本地和远程2.1.1 本地 Git Hook&#xff0c;由提交和合并等操作触发&#xff1a;2.1.2 远程 Git Hook&#xff0c;运行在网络操作上&#xff0c;例如接收推送的提交&#xff1a; 3. 操作步骤3.1 对所有的仓…

Linux 命令pwd

命令作用 pwd是Linux中一个非常有用而又十分简单的命令&#xff0c;pwd是词组print working directory的首字母缩写&#xff0c;即打印工作目录&#xff1b;工作目录就是你当前所处于的那个目录。 pwd始终以绝对路径的方式打印工作目录&#xff0c;即从根目录&#xff08;/&am…

半同步复制与MHA高可用架构设计

各位道友好&#xff0c;鼠鼠我呀校招刚通过了移动的面试 &#xff0c;但是安排的岗位是偏远县城里面的岗位&#xff0c;各位能给给建议吗&#xff1f;鼠鼠我啊真不想有时候变成销售员去卖产品&#xff01;&#xff01;&#xff01; 半同步复制与MHA高可用架构设计 一、半同步复…

力扣202题 快乐数 双指针算法

快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&#…

LeetCode(44)存在重复元素 II【哈希表】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 存在重复元素 II 1.题目 给你一个整数数组 nums 和一个整数 k &#xff0c;判断数组中是否存在两个 不同的索引 i 和 j &#xff0c;满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在&#xff0c;返回 true &#xf…

.net-去重的几种情况

文章目录 前言1. int 类型的list 去重2. string类型的 list 去重3. T泛型 List去重4. 使用HashSet List去重5. 创建静态扩展方法 总结 前言 .net 去重的几种情况 1. int 类型的list 去重 // List<int> List<int> myList new List<int>(){ 100 , 200 ,100…

波奇学C++:C++11的可变参数模板和emplace

可变参数模板 // args是参数包 template<class T,class ...Args> void _ShowList(T value, Args... args) {cout << sizeof...(args) << endl; // 2cout << value << " ";/*_ShowList(args...);*/} int main() {_ShowList(1,2,3); re…

CSS 在性能优化方面的实践

前言 CSS&#xff08;层叠样式表&#xff09;是一种用于描述网页外观和格式的语言。随着网页变得越来越复杂&#xff0c;CSS文件的大小也随之增加&#xff0c;这可能会对网页性能产生负面 .box {width: 100px;height: 100px;transition: transform 0.3s; }.box:hover {transf…

算法通关村第一关—链表高频面试题(白银)

链表高频面试题 一、五种方法解决两个链表的第一个公共子节点的问题 面试 02.07.链表相交1.首先想到的是暴力解&#xff0c;将第一个链表中的每一个结点依次与第二个链表的进行比较&#xff0c;当出现相等的结点指针时&#xff0c;即为相交结点。虽然简单&#xff0c;但是时间…

SS6810R40V/1A 步进电机驱动芯片 替代ROHM BD68610EFV

SS6810R 是一款由 PWM 电流驱动的双极低功 耗电机驱动集成芯片。 SS6810R 有两路 H 桥驱 动&#xff0c;最大输出 40V /1A。输入接口采用 Pala-IN 的驱 动方式&#xff0c;电流衰减模式可选择为快衰减、慢衰减和 混合衰减&#xff0c;且可以任意设置快衰减与慢衰减的比 例…

【Linux】firewall防火墙配置-解决Zookeeper未授权访问漏洞

背景&#xff1a; zookeeper未授权访问漏洞&#xff0c;进行限制访问&#xff0c;采用防火墙访问策略 配置步骤&#xff1a; ##查看firewall配置清单 firewall-cmd --list-all ##查到为关闭态&#xff0c;启动防火墙 systemctl start firewalld ## 添加端口&#xff0c;这里…

自动驾驶DCLC 功能规范

目录 1 概述Summary....................................................................................................... 4 1.1 目的Purpose....................................................................................................... 4 1.2 范围Ran…

主流数据库类型总结

前言&#xff1a;随着互联网的高速发展&#xff0c;为了满足不同的应用场景&#xff0c;数据库的种类越来越多容易混淆&#xff0c;所以有必要在此总结一下。数据库根据数据结构可分为关系型数据库和非关系型数据库。非关系型数据库中根据应用场景又可分为键值&#xff08;Key-…