【C语言】可变参数列表va_list
本篇博客让我们来认识一下C语言学习过程中往往被忽略的可变参数列表
所谓可变参数,就是一个不限定参数数量的函数,我们可以往里面传入任意个数的参数,以达成某些目的。
关联:C++11可变模板参数
1.函数
#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);
1.1 va_start
void va_start(va_list ap, last_arg);
- ap: 这是一个 va_list 类型的对象,它用来存储通过 va_arg 获取额外参数时所必需的信息
- 这个函数的作用是初始化
ap变量,它与 va_arg 和 va_end 函数一起使用。
- last_arg 是最后一个传递给函数的已知的固定参数,即省略号之前的参数。
要想设置一个带可变参数的函数,函数声明是下面这样的
void test(int a,int b, ...);
这里出现的省略号就是可变参数的特征,而变量b就是va_start函数需要的last_arg
1.2 va_arg
type va_arg(va_list ap, type);
这个函数的作用是来提取可变参数列表中的参数。注意,每次提取的参数是直接返回的,并没有放到变量ap中。
每次对va_arg的调用都会修改ap,以便下次调用时,返回下一个参数;推断参数的时候需要指定type,如果当前参数类型和type不统一,就会发生不可预知的错误(man手册里面说的)
If ap is passed to a function that uses va_arg(ap,type) then the value of ap is undefined after the return of that function.
如果ap被传递给va_arg(ap,type),则在该函数返回后,ap的值未定义。
1.3 va_end
void va_end(va_list ap);
每一个va_start都需要有一个配套的va_end,其用于清空ap
可以把他俩的关系理解为malloc/free,记得加上就行
1.4 va_copy
这个函数的作用是将可变参数列表从第二个参数src拷贝到第一个参数dest
void va_copy(va_list dest,va_list src);
其也能够初始化dest。调用了va_copy后,无须调用va_start初始化dest,但va_end还是需要的。
2.简单示例
2.1 打印多个参数
#include<stdarg.h>
#include<stdio.h>
int print(int num_args,...)
{va_list ap;va_start(ap,num_args);//初始化可变参数for(int i=0;i<num_args;i++){printf("%d ",va_arg(ap,int));}printf("\n");va_end(ap);//结束对ap的使用
}int main()
{print(5,1,2,3,4,5,6,7,8,9);return 0;
}
运行该函数,会打印如下结果
$ ./test
1 2 3 4 5
这就表明了,...省略号之前的参数,和va_arg返回可变参数其实是没有关系的。
int print(int num_args,...)
{va_list ap;va_start(ap,num_args);//初始化可变参数for(int i=0;i<8;i++){printf("%d ",va_arg(ap,int));}printf("\n");va_end(ap);//结束对ap的使用
}int main()
{print(5,1,2,3,4,5,6,7,8,9,10);return 0;
}
即便在最后都没有使用num_args,也不会影响结果的正确性。va_start需要这个参数,其实是用来标识可变参数的起点。
$ ./test
1 2 3 4 5 6 7 8
2.2 多参数求和
#include<stdarg.h>
#include<stdio.h>
// 采用可变参数,第一个参数用于标识参数数量
int sum(int num_args, ...)
{int val = 0;va_list ap;int i;va_start(ap, num_args);for(i = 0; i < num_args; i++){val += va_arg(ap, int);}va_end(ap);return val;
}void test1()
{printf("10、20 和 30 的和 = %d\n", sum(3, 10, 20, 30) );printf("4、20、25 和 30 的和 = %d\n", sum(4, 4, 20, 25, 30) );
}
运行如下
$ ./test
10、20 和 30 的和 = 60
4、20、25 和 30 的和 = 79
3.利用可变参数实现log类
现在有了可变参数,我们就可以接用这个参数来进行日志的打印了
#pragma once#include <cstdio>
#include <ctime>
#include <cstdarg>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <stdlib.h>#define DEBUG 0
#define NOTICE 1
#define WARINING 2
#define FATAL 3const char *log_level[]={"DEBUG", "NOTICE", "WARINING", "FATAL"};// 采用可变参数列表
void logging(int level, const char *format, ...)
{assert(level >= DEBUG || level <= FATAL);char *name = getenv("USER");// 获取环境变量中的用户(执行命令的用户)char logInfo[1024];// 获取可变参数列表va_list ap; // ap -> char*va_start(ap, format);vsnprintf(logInfo, sizeof(logInfo)-1, format, ap);va_end(ap); // ap = NULL// 根据日志等级选择打印到stderr/stdoutFILE *out = (level == FATAL) ? stderr:stdout;// 格式化打印到文件中fprintf(out, "%s | %u | %s | %s\n", \log_level[level], \(unsigned int)time(nullptr),\name == nullptr ? "unknow":name,\logInfo);
}
3.1 vsnprint
作用:使用vsnprintf()用于向一个字符串缓冲区打印格式化字符串,且可以限定打印的格式化字符串的最大长度。
此函数需要C99或者C++11及以上版本才能支持。
int vsnprintf(char* sbuf, size_t n, const char* format, va_list arg);
- 第一个参数:目标缓冲区(字符数组)
- 第二个参数,限定最多打印到缓冲区的字符数量为
n-1个(留位置给\0) - 第三个参数,打印的格式(如
%d:%s) - 第四个参数,可变参数arg,需要用
va_start初始化
返回:成功打印到sbuf中的字符的个数,不包括末尾追加的\0。如果格式化解析失败,则返回负数。
用这个函数,就能把我们的来源字符串给输入到缓冲区char logInfo[1024];中
3.2 fprintf
使用fprintf,将printf的输出打印到指定文件中;用法和printf是一样的
int fprintf(FILE *stream, const char *format, ...);
这样是为了区分stderr/stdout。同时添加上执行命令的用户信息,以及当前的时间戳
fprintf(out, "%s | %u | %s | %s\n", \log_level[level], \(unsigned int)time(nullptr),\name == nullptr ? "unknow":name,\logInfo);
3.3 运行结果
int main()
{logging(DEBUG, "socket create success: %d", 114514);logging(FATAL, "socket:%s:%d", strerror(errno), 11234);return 0;
}
$ ./test
DEBUG | 1675322313 | muxue | socket create success: 114514
FATAL | 1675322313 | muxue | socket:Success:11234
The end
对于可变参数的简单介绍就到这里!基本的使用能看懂久OK啦!
相关文章:
【C语言】可变参数列表va_list
本篇博客让我们来认识一下C语言学习过程中往往被忽略的可变参数列表 所谓可变参数,就是一个不限定参数数量的函数,我们可以往里面传入任意个数的参数,以达成某些目的。 关联:C11可变模板参数 1.函数 #include <stdarg.h>…...
CentOS7.6 MySQL8安装
1 检查是否安装过 MySQL rpm -qa | grep -i mysqlmariadb rpm -qa | grep mariadb2 卸载之前的安装 MySQL rpm -e --nodeps 软件名 //强力删除,对相关依赖的文件也进行强力删除卸载 rpm -e --nodeps mariadb-libs-5.5.60-1.el7_5.x86_643 官网下载 MySQL :: D…...
安装Tomcat的步骤?
首先先完成JDK配置,javac -version 检测 1.把tomcat下载到本地硬盘 2.创建tomcat8.0文件夹,完成解压(免安装)4.打开解压之后的目录,进入bin目录,双击startup.bat,启动tomcat5.可以看到弹出一个黑色的窗口,不要关闭,如果关闭意味着…...
Redis之分布式锁
随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的 Java API并不能提供分布式锁的能力。为了解决这个问题…...
2022年中国前10电商GMV总结
我是卢松松,点点上面的头像,欢迎关注我哦! 1,阿里8万亿;2,京东3万亿;3,拼多多3万亿;4,小程序私域电商3万亿;5,抖音电商1.4万亿。6,抖音本地生活服务电商600亿。7…...
ES6新增扩展:字符串-数值-数组-函数-对象
ES6新增扩展字符串的扩展判断字符串是否包含在另一个字符中字符串补全字符串重复消除字符串空格replaceAll()替换全部字符串at字符串匹配输出数值的扩展数值分隔符检测数值是否有限检测是否为NaNNumber.parseInt()、Number.parseFloat()isInteger()判断是否为整数Math.sign()判…...
python中import原理
0. 前言 在 python 中引入 Module 是再常见不过了,那么当我们 import 时它做了什么事情呢?它是如何加载 Module 使用的呢? 1. 什么是 module? 一般,Module 是一个后缀为 .py 的文件,其 module 名称一般…...
《Qt6开发及实例》6-4 显示SVG格式图片
目录 一、简介与设计 1.1 简介 1.2 设计 二、SvgWidget 2.1 鼠标滚轮事件 三、svgwindow 四、MainWindow 一、简介与设计 1.1 简介 1、SVG 的英文全称是 Scalable Vector Graphics,即可缩放的矢量图形。它是由万维网联盟(W3C)在 200…...
OpenGL ES 绘制一张图片
GLSL 语法与内建函数 GLSL 的修饰符与数据类型 GLSL 中变量的修饰符 const:修饰不可被外界改变的常量attribute:修饰经常更改的变量,只可以在顶点着色器中使用uniform:修饰不经常更改的变量,可用于顶点着色器和片段…...
Python 之 Pandas DataFrame 数据类型的行操作和常用属性和方法汇总
文章目录一、DataFrame 行操作1. 标签选取2. 数值型索引和切片3. 切片操作多行选取4. 添加数据行4.1 追加字典4.2 追加列表5. 删除数据行二、常用属性和方法汇总1. 转置2. axes3. dtypes4. empty5. columns6. shape7. values8. head() & tail()9. 修改列名 rename()10. inf…...
MacOS下载钉钉直播回放视频的Python最新解决方案
tags: Python MacOS Tips 写在前面 之前写过一篇关于用Charles抓包下载钉钉直播回放视频的方法, 那会还是可以直接通过FFmpeg下载m3u8链接并且直接合并的, 但是现在直接上FFmpeg会出现403, 所以还是用别的方法来做吧. 后来发现抓包找到的m3u8不是加密视频流, 那就直接下载ts…...
2023年测试人跳槽新功略,涨薪10K+
软件测试是如何实现涨薪的呢?很多人眼中的软件测试岗位可能是简单的,技术含量不是那么高,就是看看需求、看业务、设计文档、然后点一点功能是否实现,再稍微深入一点就是测试下安装部署时会不会出现兼容性问题,以及易用…...
RabbitMQ之Work Queues
Work Queues 工作队列(又称任务队列)的主要思想是避免立即执行资源密集型任务,而不得不等待它完成。相反我们安排任务在之后执行。我们把任务封装为消息并将其发送到队列。在后台运行的工作进程将弹出任务并最终执行作业。当有多个工作线程时,这些工作线程将一起处理这些任务…...
CRM哪家好?这5个CRM管理系统很好用!
CRM哪家好?这5个CRM管理系统很好用! CRM(Customer Relationship Management)即客户关系管理,能够帮助提高客户的价值、满意度、赢利性和忠实度,缩减销售周期和销售成本、增加收入、寻找扩展业务所需的新的市场和渠道,…...
国内ce认证机构有哪些 国内十大CE认证机构排名 做ce认证的公司推荐
CE认证,是任何企业的任何产品走进欧盟市场的硬性要求。挑选CE认证机构,一定要认准拥有正规资质的机构/企业,例如中国质量认证中心CQC、CVC威凯、CTI华测检测,以及TV南德认证、安博检测、万泰认证等。本文中,MaiGoo小编…...
多If函数封装的策略
在工作中我们经常遇到有多个if的判读函数,这是一件很正常的事情,如下: let order function (orderType, isPay, count) {if (orderType 1) {// 充值 500if (isPay true) {// 充值成功console.log(中奖100元)} else {if (count > 0) {c…...
238. 银河英雄传说
Powered by:NEFU AB-IN Link 文章目录238. 银河英雄传说题意思路代码238. 银河英雄传说 题意 有一个划分为 N列的星际战场,各列依次编号为 1,2,…,N 有 N艘战舰,也依次编号为 1,2,…,N,其中第 i号战舰处于第 i列。 有 T条指令,每…...
centos7 开机自启动自定义脚本
centos7 开机自启动自定义脚本背景配置自启动jar1.首先书写自启动脚本2.在rc.local中加入脚本reboot测试docker版本的自启动背景 项目中有遇到2个问题, 1: 使用java启动jar包 2: docker容器中自启动个服务。 这2个都要使用linux的开机自启动问…...
【Linux】动静态库的制作
🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉动静库和静…...
数据备份学习笔记2
Linux实现本地备份的命令: mkdir -p /root/backup/date "%Y-%m-%d" tar -zcvPf /root/backup/date "%Y-%m-%d"/test20230221.tar.gz /root/test20230221/ 我们再看下tar命令选项: tar -czvf txt3.tar.gz txt3 tar -xvf txt4.tar.g…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
