va_list/va_start/va_end/var_arg可变参数的使用
个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
做日志打印或其它可变参数处理时,通常我们会想到使用va_list/va_start/va_end做可变参数的收集和处理。使用这种方式处理可变参数比较通用,同时适用于c与c++中。
1. 关于va_list的理解
va_list是一个变参的结构,通常它的结构中,会有一个起始参数的地址。
就像我们经常见到的main函数中的那样:argc-argcount参数个数,argv-argvalues参数指针数组
int (int argc, char** argv)
我们通过argc知道了参数的个数,通过argv获取到每个参数的指针。
va_list初始化后,提供一个类似argv的变量,用于做参数的遍历处理,但实际情况比这个复杂许多,内部提供的可能是参数位于寄存器上地址与偏移、参数位于栈地址与偏移。
va_list初始化后,通常并不能用于获取参数个数,不能提供类似argc的获取;参数个数需要额外的判断,例如vprintf基于formart的%d,%s等来获取需要输入的参数个数。
对于va_list结构,标准库没有提供直接读取va_list内部信息的函数,对于不同操作系统结构可能会不同,另外可以使用 va_arg 逐个提取参数,或者使用 va_copy 复制 va_list。
相关对va_list的处理函数
va_start:初始化一个可变参数列表var_list内部的指针;
va_arg:获取下一个参数的值
va_end:清理一个可变参数列表var_list;
va_copy(C99+):复制参数列表状态
2. 关于va_start/va_end
通常var_start与var_end成对出现,va_start负责初始化一个var_list可变参数列表指针,va_end负责使用完清理。
void va_start(va_list ap, prev_param);
void va_end(va_list ap);
参数ap:一个 va_list 类型的变量,用于存储可变参数列表的内部状态。
参数prev_param:可变参数列表之前的最后一个固定
var_start与var_end使用时,要特别注意的一个点是,成对出现与使用,并且如果使用过一次var_list后,需要重新初始化才能再次使用;原因是因为使用过的va_list内部的指针偏移被修改过了,再次使用的话,偏移未重置,读取的参数可能就有问题了或越界了。
一个使用var_start与var_end两次的样例,形如如下的效果:
先使用一次vsnprintf获取输出字符串长度,然后再申请字符串,然后再调用一遍vsnprintf把字符串输出到buffer中。
std::string LogToStr(const char* format, ...) {// init va_listva_list valist;va_start(valist, format);// fill buffer int length = vsnprintf(nullptr, 0, format, valist);std::string buffer;if (length > 0) {// destory and reinit valist va_end(valist);va_start(valist, format);// alloc size and fill buffer buffer.resize(length + 1);length = vsnprintf(&buffer[0], length + 1, format, valist);}// destory valist and return bufferva_end(valist);return buffer;
}
3. 接受va_list的系统函数
直接接受va_list的系统函数也比较多,常见的有vprintf, vfprintf, vsnprintf等:
int vprintf(const char* format, va_list ap);
int vfprintf(FILE* stream, const char* format, va_list ap);
int vsnprintf(char* buffer, size_t size, const char* format, va_list ap);
使用vprintf,打印到标准输出的样例:
void print_formatted(const char* format, ...) {va_list args;va_start(args, format);vprintf(format, args);va_end(args);
}
使用vfprintf,输出到文件的样例:
void log_to_file(FILE* file, const char* format, ...) {va_list args;va_start(args, format);vfprintf(file, format, args);va_end(args);}
使用vsnprintf,输出到定长字符串的样例:
void safe_format_string(char* buffer, size_t size, const char* format, ...) {va_list args;va_start(args, format);vsnprintf(buffer, size, format, args);va_end(args);}
| 函数/宏名称 | 作用 |
|---|---|
vprintf | 将格式化字符串输出到标准输出。 |
vfprintf | 将格式化字符串输出到指定文件流。 |
vsprintf | 将格式化字符串存储到指定缓冲区。 |
vsnprintf | 将格式化字符串存储到指定缓冲区,并确保不超出缓冲区大小。 |
vscanf | 从标准输入读取格式化数据。 |
vfscanf | 从指定文件流读取格式化数据。 |
vsscanf | 从指定字符串读取格式化数据。 |
vfwprintf | 将格式化后的宽字符串输出到指定文件流。 |
vswprintf | 将格式化后的宽字符串存储到指定缓冲区。 |
vsyslog | 将格式化日志输出到系统日志。 |
vsnprintf_s | 安全版本的 vsnprintf,确保不超出缓冲区大小。 |
除了这一些能接受va_list的函数来直接调用外,还可以直接遍历va_list使用。
可以使用var_arg来一个一个取参数使用:
type va_arg(va_list ap, type);
int SumValues(const int count, ...) {va_list args;va_start(args, count);int sum = 0;for (int i=0; i<count; i++){sum += va_arg(args, int);}va_end(args);return sum;
}
其它,stl库模版实现可变参数
另外还一种stl库中带的可变参数模板形式:
template<typename... Args>
void myFunction(Args... args) {int count = sizeof...(args);// 处理args
}template<typename... Args>
auto sum(Args... args) {return (args + ...);
}int main() {std::cout << sum(1, 2, 3, 4) << std::endl; // 输出: 10std::cout << sum(1.5, 2.5, 3.5) << std::endl; // 输出: 7.5return 0;
}
个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
相关文章:
va_list/va_start/va_end/var_arg可变参数的使用
个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 做日志打印或其它可变参数处理时,通常我们会想到使用va_list/va_start/va_end做可变参数的收集和处理。使用这种方式处理可变参数比较通用,同时适用于c与c中。 1. 关于va_list的理解 v…...
【linux网络(4)】传输层协议详解(上)
目录 前言1. UDP协议报文详解2. TCP协议的报文格式3. TCP的确认应答机制4. TCP的连接管理机制1. TCP三次握手的过程2. TCP四次挥手的过程 5. 总结 前言 上一篇文章介绍了应用层中最重要的http协议,本篇文章将讲解传输层的两个协议: TCP和UDP. 由于UDP是一种简洁的协…...
【Docker】dockerfile识别当前构建的镜像平台
在编写dockerfile的时候,可能会遇到需要针对不同平台进行不同操作的时候,这需要我们对dockerfile进行针对性修改。 比如opencv的依赖项libjasper-dev在ubuntu18.04上就需要根据不同的平台做不同的处理,关于这个库的安装在另外一篇博客里面有…...
【esp32-uniapp】uniapp小程序篇02——引入组件库
一、引入组件库(可自行选择其他组件库) 接下来介绍colorUI、uview plus的安装,其他的安装可自行查找教程 1.colorUI weilanwl/coloruicss: 鲜亮的高饱和色彩,专注视觉的小程序组件库 下载之后解压,将\coloruicss-ma…...
使用C# 如何获取本机连接的WIFI名称[C# ---1]
前言 楼主最近在写一个WLAN上位机,遇到了使用C#查询SSID 的问题。CSDN上很多文章都比较老了,而且代码过于复杂。楼主自己想了一个使用CMD来获得SSID的方法 C#本身是没有获得WINDOWS网路信息的能力,必须要用系统API,WMI什么的&…...
机器学习优化算法:从梯度下降到Adam及其实验改进
机器学习优化算法:从梯度下降到Adam及其实验改进 在机器学习和深度学习领域,模型的训练过程本质上是一个优化问题。优化算法的作用是通过调整模型参数,使得模型在给定的数据 集上实现最优性能。而优化算法的效率和效果直接决定了模型的收敛速度和最终表现。 一、优化算法的…...
K8s 中 Ingress-Nginx 结合负载均衡器(Ingress nginx combined with load balancer)
K8s 中 Ingress-Nginx 结合负载均衡器(LB)的部署全解析 在 K8s的世界里,有效地管理和路由进入集群的外部流量是至关重要的。Ingress-Nginx 作为一款强大的 Ingress 控制器,搭配负载均衡器(LB),…...
MATLAB中savefig函数用法
目录 语法 说明 示例 将当前图窗保存到 FIG 文件 将多个图窗保存到 FIG 文件 使用 compact 选项保存图窗 savefig函数的功能是将图窗和内容保存到 FIG 文件。 语法 savefig(filename) savefig(H,filename) savefig(H,filename,compact) 说明 savefig(filename) 将当前…...
Windows系统中Docker可视化工具对比分析,Docker Desktop,Portainer,Rancher
Docker可视化工具对比分析,Docker Desktop,Portainer,Rancher Windows系统中Docker可视化工具对比分析1. 工具概览2. Docker Desktop官网链接:主要优点:主要缺点:版本更新频率: 3. Portainer官网…...
创业项目怎么找?
寻找创业项目需要系统的方法和策略,以下是一些有效的途径和方法,帮助你找到合适的创业项目: 1. 从自身出发 兴趣爱好:选择自己感兴趣的领域,更容易坚持并投入热情。例如,如果你对网络购物感兴趣࿰…...
【机器学习】自定义数据集,使用scikit-learn 中K均值包 进行聚类
一、K 均值算法简介 K 均值算法的目标是将数据集划分为 K 个簇,使得每个数据点属于离它最近的簇中心(centroid)所代表的簇。 K均值聚类算法步骤 ① 初始化: 随机选择原始数据的K个数据点作为初始质心(聚类中心&…...
RocketMQ 系列文章
目录 使用RocketMQ 的业务系统怎么处理消息的重试? 使用RocketMQ 的业务系统怎么保证消息处理的幂等性? 使用RocketMQ 的业务系统怎么处理消息的积压? RocketMQ 怎么保证消息的可靠性? RocketMQ 怎么保证消息的顺序性的? RocketMQ 的 Topic 和消息队列MessageQueue信…...
进阶数据结构——高精度运算
目录 前言一、高精度运算的定义与背景二、高精度运算的实现方式三、高精度运算的算法实现四、高精度运算的应用场景五、代码模版(c)六、经典例题1.[高精度加法](https://www.lanqiao.cn/problems/1516/learning/?page1&first_category_id1&name…...
42【语言的编码架构】
不同语言采用的编码架构不一样 火山采用:UTF-16 易语言采用:GBK php采用:UTF-8 这个编码架构指的就是文本所代表的字节集,比如易语言中“你好”表示的就是{196,227,186,195} 窗口程序集名保 留 保 留备 注窗口程序集_启动窗口 …...
设计模式Python版 原型模式
文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:关注类和对…...
用 JavaScript 打造交互式表格:添加与删除行功能
前言 在网页开发中,创建交互式表格是很常见的。今天我们通过一个示例,来展示如何使用 HTML、CSS 和 JavaScript 实现一个能够动态添加和删除行的表格,并详细解释其中 JavaScript 部分的代码逻辑。 功能展示 初始状态:页面加载后…...
Linux02——Linux的基本命令
目录 ls 常用选项及功能 综合示例 注意事项 cd和pwd命令 cd命令 pwd命令 相对路径、绝对路径和特殊路径符 特殊路径符号 mkdir命令 1. 功能与基本用法 2. 示例 3. 语法与参数 4. -p选项 touch-cat-more命令 1. touch命令 2. cat命令 3. more命令 cp-mv-rm命…...
服务器虚拟化实战:架构、技术与最佳实践
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 1. 引言 服务器虚拟化是现代 IT 基础设施的重要组成部分,通过虚拟化技术可以提高服务器资源利用率、降低硬件成本&am…...
.Net WebAPI -[HttpPut(“{fileServiceId:int}“)]
[HttpPut("{fileServiceId:int}")] 这个写法是 ASP.NET Core 中的一个路由特性,用于定义一个 HTTP PUT 请求的路由,并指定路由参数的类型。 解析 HttpPut [HttpPut]: 这是一个 ASP.NET Core 的路由特性,用于标记一个方…...
AI大模型开发原理篇-1:语言模型雏形之N-Gram模型
N-Gram模型概念 N-Gram模型是一种基于统计的语言模型,用于预测文本中某个词语的出现概率。它通过分析一个词语序列中前面N-1个词的出现频率来预测下一个词的出现。具体来说,N-Gram模型通过将文本切分为长度为N的词序列来进行建模。 注意:这…...
[250201] isd v0.3.0 发布:全新快捷键逻辑及其他改进 | Puma 6.6.0 版本发布
目录 isd v0.3.0 发布:全新快捷键逻辑及其他改进Puma 6.6.0 版本发布🆕 新特性🛠️Bug 修复💪 性能改进🔄 代码重构 isd v0.3.0 发布:全新快捷键逻辑及其他改进 isd (Interactive Systemd) 是一款文本用户…...
修改题注标签
为了防止原博主删帖,故转到自己账号中,出处如下 转载:(152条消息) 修改题注标签_Z_shsf的博客-CSDN博客_seq图arabic怎么解决 问题:论文中存在 标签图1- 和标签图 ,如何合并两种标签 成为图 并一起计数 按 AltF9 查…...
pytorch实现循环神经网络
人工智能例子汇总:AI常见的算法和例子-CSDN博客 PyTorch 提供三种主要的 RNN 变体: nn.RNN:最基本的循环神经网络,适用于短时依赖任务。nn.LSTM:长短时记忆网络,适用于长序列数据,能有效解决…...
Python从零构建macOS状态栏应用(仿ollama)并集成AI同款流式聊天 API 服务(含打包为独立应用)
在本教程中,我们将一步步构建一个 macOS 状态栏应用程序,并集成一个 Flask 服务器,提供流式响应的 API 服务。 如果你手中正好持有一台 MacBook Pro,又怀揣着搭建 AI 聊天服务的想法,却不知从何处迈出第一步,那么这篇文章绝对是你的及时雨。 最终,我们将实现以下功能: …...
leetcode 2080. 区间内查询数字的频率
题目如下 数据范围 示例 这题十分有意思一开始我想对每个子数组排序二分结果超时了。 转换思路:我们可以提前把每个数字出现的位置先记录下来形成集合, 然后拿着left和right利用二分查找看看left和right是不是在集合里然后做一个相减就出答案了。通过…...
深入了解 SSRF 漏洞:原理、条件、危害
目录 前言 SSRF 原理 漏洞产生原因 产生条件 使用协议 使用函数 漏洞影响 防御措施 结语 前言 本文将深入剖析 SSRF(服务端请求伪造)漏洞,从原理、产生原因、条件、影响,到防御措施,为你全面梳理相关知识&am…...
11.QT控件:输入类控件
1. Line Edit(单行输入框) QLineEdit表示单行输入框,用来输入一段文本,但是不能换行。 核心属性: 核心信号: 2. Text Edit(多行输入框) QTextEdit表示多行输入框,也是一个富文本 & markdown编辑器。并且能在内容超…...
Cesium+Vue3教程(011):打造数字城市
文章目录 Cesium打造数字城市创建项目加载地球设置底图设置摄像头查看具体位置和方向添加纽约建筑模型并设置样式添加纽约建筑模型设置样式划分城市区域并着色地图标记显示与实现实现飞机巡城完整项目下载Cesium打造数字城市 创建项目 使用vite创建vue3项目: pnpm create v…...
Windows系统本地部署deepseek 更改目录
本地部署deepseek 无论是mac还是windows系统本地部署deepseek或者其他模型的命令和步骤是一样的。 可以看: 本地部署deepsek 无论是ollama还是部署LLM时候都默认是系统磁盘,对于Windows系统,我们一般不把应用放到系统盘(C:)而是…...
基于Python的药物相互作用预测模型AI构建与优化(下.代码部分)
四、特征工程 4.1 分子描述符计算 分子描述符作为量化分子性质的关键数值,能够从多维度反映药物分子的结构和化学特征,在药物相互作用预测中起着举足轻重的作用。RDKit 库凭借其强大的功能,为我们提供了丰富的分子描述符计算方法,涵盖了多个重要方面的分子性质。 分子量…...
