C++之va_start、vasprintf、va_end应用总结(二百二十六)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

1.前言
本篇目的:C++之va_start、vasprintf、va_end应用总结。
在C/C++语言中,va_start、vasprintf和va_end是与可变参数相关的函数。它们通常与stdarg.h头文件一起使用。
-
va_start函数:va_start函数用于初始化可变参数列表。它接受两个参数:第一个参数是一个va_list类型的变量,第二个参数是最后一个固定参数的前一个参数的名称。- 这个函数将
va_list类型变量初始化为指向可变参数列表的起始位置。
-
vasprintf函数:vasprintf函数用于将格式化的可变参数输出到动态分配的字符串中。- 它接受两个参数:第一个参数是一个指向
char指针的指针,第二个参数是一个格式化字符串。 - 这个函数会根据格式化字符串和可变参数列表生成一个动态分配的字符串,并将指针保存在第一个参数所指向的位置。
-
va_end函数:va_end函数用于结束可变参数的获取。- 它接受一个参数,即一个
va_list类型的变量。 - 这个函数对可变参数列表进行清理,使其无法再被访问。
通常在需要处理可变参数的情况下,使用实现Printf风格的函数或者处理命令行参数时。
2.应用实例
<1>.v1.0
#include <stdio.h>
#include <stdarg.h>void sum(int count, ...)
{va_list args;int total = 0;// 初始化可变参数列表va_start(args, count);// 遍历可变参数列表并求和for (int i = 0; i < count; i++){int num = va_arg(args, int);total += num;}// 结束可变参数列表va_end(args);printf("Sum: %d\n", total);
}int main()
{sum(3, 1, 2, 3); // 输出 Sum: 6return 0;
}
va_start是一个宏,用于处理可变参数列表。它的原理是基于C语言的可变参数机制。
va_start宏的工作原理如下:
-
首先,通过传入的参数列表的类型信息和格式化字符串来确定参数列表的起始位置。
-
然后,通过指针运算和类型大小来计算出参数列表中各个参数的位置。
-
最后,将参数列表位置信息保存在一个
va_list类型的变量中,供后续函数进行处理。
va_start宏的实现通常依赖于编译器和操作系统的底层支持。它使用了一些机制来获取参数列表的信息,如栈帧结构、类型信息、指针运算等。
具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:
-
获取栈帧指针:
va_start宏需要通过访问栈来获取参数列表的位置信息。它首先获取当前函数的栈帧指针,可以通过编译器提供的相关函数或底层汇编指令来实现。 -
计算参数列表位置:通过栈帧指针和参数类型大小,
va_start宏可以计算出参数列表中各个参数的位置。这通常涉及指针运算,根据参数类型大小来移动指针位置。 -
保存参数列表信息:
va_start宏将参数列表位置信息保存在一个va_list类型的变量中,以便后续的函数进行处理。可以将栈帧指针和计算得到的参数列表位置信息存储在va_list变量中。
va_start宏使用一些编译器和操作系统提供的底层机制来实现可变参数的处理。具体实现可能会因编译器和操作系统的不同而异,也可能受到编译器的优化策略的影响。
<2>.v2.0
#include <stdio.h>
#include <stdarg.h>char* format_string(const char* format, ...)
{va_list args;char* str;// 初始化可变参数列表va_start(args, format);// 格式化字符串并存储到动态分配的字符串中int length = vasprintf(&str, format, args);// 结束可变参数列表va_end(args);printf("Formatted String: %s\n", str);printf("String Length: %d\n", length);return str;
}int main()
{char* result = format_string("Hello %s, your age is %d.", "John", 25);// 输出 Formatted String: Hello John, your age is 25.// 输出 String Length: 30free(result); // 释放动态分配的字符串return 0;
}
va_end是一个宏,用于结束对可变参数列表的访问。它的原理是基于C语言的可变参数机制。
va_end宏的工作原理如下:
-
首先,它接收一个
va_list类型的变量作为参数,该变量保存了参数列表的位置信息。 -
接着,通过一系列机制(如编译器和操作系统的底层支持)实现将参数列表进行清理和释放的操作。
-
最后,将
va_list类型的变量标记为无效,以确保之后对它的访问是无效的。
具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:
-
清理参数列表:
va_end宏根据参数列表的位置信息,使用特定的机制将参数列表进行清理。它可能涉及释放资源、清理栈上的参数值等操作。具体的清理操作由编译器和操作系统提供的底层支持来实现。 -
使
va_list变量失效:为了确保在之后对va_list变量的访问是无效的,va_end宏将该变量标记为无效。这样可以避免误用已经结束的参数列表。
va_end宏的实现依赖于编译器和操作系统的底层支持。具体实现的细节可能会因编译器和操作系统的不同而异。但无论实现细节如何,va_end宏的目标都是确保正确清理和释放可变参数列表所占用的资源,并将va_list变量标记为无效。
<3>.v3.0
#include <iostream>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <string>using namespace std;string AStringPrintf(const char *format, ...) {va_list ap;va_start(ap, format);char *buffer;int bufferSize = vasprintf(&buffer, format, ap);va_end(ap);if(bufferSize < 0) {return string();}string result(buffer);free(buffer);buffer = NULL;return result;
}int main(){char str[64]={1,2,3,5,6,7,8,9};string buf = AStringPrintf(str);printf("buf = %s\n",buf.c_str());
}
-
vsnprintf函数接收一个格式化字符串和一个va_list类型的参数列表。利用格式化字符串,它将参数列表中的数据转换为相应的字符串格式。 -
首先,
vsnprintf函数根据格式化字符串中的格式指示符,逐个读取参数列表的值,并根据指示符的要求对其进行格式化。 -
然后,
vsnprintf函数根据格式化的结果,将其写入到指定的缓冲区中。它会确保写入的数据不超过指定的缓冲区大小。 -
最后,
vsnprintf函数会在写入完成后,返回实际写入的字符数(不包括结尾的’\0’)。如果缓冲区大小不足以容纳格式化后的字符串,vsnprintf函数会截断字符串,但仍然会返回实际要写入的字符数。
需要注意的是,由于vsnprintf函数是经过格式化而得到的字符串的长度是不确定的,因此在使用之前需要分配足够的缓冲区来存储格式化后的字符串,以避免缓冲区溢出的情况发生。
vsnprintf函数是一个用于以固定格式将可变参数格式化为字符串的函数。它将格式化的结果写入指定的缓冲区,并返回实际写入的字符数。这个函数在C++中可用于处理可变参数,并将其转换为字符串格式。
<4>.v4.0
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>void dynamic_print(const char* format, ...)
{va_list args;va_start(args, format);char* dyn_str = NULL;size_t str_length = 0;// 计算动态生成字符串所需的长度str_length = vsnprintf(NULL, 0, format, args);// 为字符串动态分配内存dyn_str = (char*)malloc(str_length + 1);// 动态生成字符串vsnprintf(dyn_str, str_length + 1, format, args);printf("%s", dyn_str);free(dyn_str);va_end(args);
}int main(){int num1 = 10;int num2 = 20;dynamic_print("Sum: %d + %d = %d\n", num1, num2, num1 + num2);return 0;
}相关文章:
C++之va_start、vasprintf、va_end应用总结(二百二十六)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
OpenCV自学笔记十一:形态学操作(一)
目录 1、腐蚀 2、膨胀 3、通用形态学函数 4、开运算 5、闭运算 1、腐蚀 腐蚀(Erosion)是数字图像处理中的一种形态学操作,用于消除图像中边界附近的细小区域或缩小对象的大小。腐蚀操作通过卷积输入图像与结构元素(也称为腐…...
封装全局异常处理
文章目录 1 定义错误码类2 定义业务异常类3 全局异常处理器4 使用5 前端请求效果总结 1 定义错误码类 可以定义各种错误码枚举,比如业务,系统相关的报错信息 /*** 错误代码* 错误码** author leovany* date 2023/09/23*/ public enum ErrorCode {SU…...
python的requests响应请求,结果乱码,即使设置了response.encoding也没有用的解决方法
一、问题 如图: 一般出现乱码,我们会有三种解决方式,如下但是图中解决了发现还是不行, response.encodingresponse.apparent_encoding通过看网页源码对response.encodingutf8指定编码格式或者直接通过response.content.decode()来获得源码 出…...
PyCharm 手动下载插件
插件模块一直加载失败,报错信息: Marketplace plugins are not loaded. Check the internet connection and refresh. 尝试了以下方法,均告失败: pip 换源Manage Plugin Repositories...HTTP 代理设置...关闭三个防火墙 最后选…...
Gnomon绑定基础(约束 IK 节点)
点约束 方向约束 父约束 目标约束 修改后 对象方向 IK控制柄 直的骨骼,指定IK怎么弯曲 直的骨骼,指定IK怎么弯曲 样条曲线 数学节点 乘除节点 混合节点 注意...
STL常用遍历,查找,算法
目录 1.遍历算法 1.1for_earch 1.2transform 2.常用查找算法 2.1find,返回值是迭代器 2.1.1查找内置数据类型 2.1.2查找自定义数据类型 2.2fin_if 按条件查找元素 2.2.1查找内置的数据类型 2.2.2查找内置数据类型 2.3查找相邻元素adjeacent_find 2.4查找指…...
BCC源码内容概览(1)
接前一篇文章:BCC源码编译和安装 本文参考官网中的Contents部分的介绍。 BCC源码根目录的文件,其中一些是同时包含C和Python的单个文件,另一些是.c和.py的成对文件,还有一些是目录。 跟踪(Tracing) exam…...
mysql限制用户登录失败次数,限制时间
mysql用户登录限制设置 mysql 需要进行用户登录次数限制,当使用密码登录超过 3 次认证链接失败之后,登录锁住一段时间,禁止登录这里使用的 mysql: 8.1.0 这种方式不用重启数据库. 配置: 首先进入到 mysql 命令行:然后需要安装两个插件: 在 mysql 命令行中执行: mysql> INS…...
从利用Arthas排查线上Fastjson问题到Java动态字节码技术(下)
上一篇从Arthas的源码引出了Java动态字节码技术,那么这一篇就从几种Java字节码技术出发,看看Arthas是如何通过动态字节码技术做到无侵入的源码增强; Java大部分情况下都是解释执行的,也就是解释.class文件,所以如果我们…...
Ubuntu中安装Anaconda 如何将 路径导入为全局变量
第一步:将你的anaconda 路径复制下来,在终端输入对应路径。 echo export PATH"/home/你的用户名/anaconda3/bin:$PATH" >> ~/.bashrc 第二步:在终端输入下面命令或者重启系统。 source ~/.bashrc 在对应的anaconda安装目…...
【QT】Qt的随身笔记(持续更新...)
目录 Qt 获取当前电脑桌面的路径Qt 获取当前程序运行路径Qt 创建新的文本文件txt,并写入内容如何向QPlainTextEdit 写入内容QTimerQMessageBox的使用QLatin1StringQLayoutC在c头文件中写#include类的头文件与直接写class加类名有何区别mutable关键字前向声明 QFontQ…...
【LeetCode-简单题】589. N 叉树的前序遍历
文章目录 题目方法一:单循环栈做法方法二:递归 题目 方法一:单循环栈做法 关键在于子节点的入栈顺序,决定了子节点的出栈顺序, 因为是前序遍历 所以压栈顺序先让右边的入栈 依次往左 这样左边的节点会在栈顶 这样下次…...
Linphone3.5.2 ARM RV1109音视频对讲开发记录
Linphone3.5.2 ARM RV1109音视频对讲开发记录 说明 这是一份事后记录,主要记录的几个核心关键点,有可能很多细节没有记上,主要是方便后面自己再找回来! 版本 3.5.2 一些原因选的是这样一个旧的版本! 新的开发最好选新一些的版…...
Unity用相机实现的镜子效果
首先登场 场景中的元素 mirror是镜子,挂着我们的脚本,Quad是一个面片。Camera是用来生成RenderTexture给面片的。里面的test1是我用来调试位置的球。 镜子size是大小,x是-2,为了反转一下贴图 相机直接可以禁用掉,用…...
计算机网络分类
按照覆盖范围分类 (1)个域网:通常覆盖范围在1~10m。 (2)局域网:通常覆盖范围在10m~1km。 (3)城域网:覆盖范围通常在5~50 km 。 &…...
AI AIgents时代 - (三.) AutoGPT和AgentGPT
前两篇讲解了Agent的原理和组件,这节我将给大家介绍两个agent项目,给出它们的工作原理和区别,并教大家亲手尝试使用 Agents🎉 🟢 AutoGPT🤖️ 我们的老朋友,之前文章也专门写过。AutoGPT 是一…...
Jmeter接口自动化和Python接口自动化,如何选择?
选择Jmeter或Python进行接口自动化测试取决于您的具体需求和环境。以下是一些可以考虑的因素: 1. 语言熟悉度:如果您对Java更熟悉,那么Jmeter可能是更好的选择。而如果您的团队或个人对Python更熟悉,那么Python可能是更好的选择。…...
Sqilte3初步教程
文章目录 安装创建数据库创建和删除表插入行数据 安装 Windows下安装,首先到下载页面,下载Windows安装软件,一般是 sqlite-dll-win32-*.zip sqlite-tools-win32-*.zip下载之后将其内容解压到同一个文件夹下,我把它们都放在了D:\…...
详解Python中的json库
目录 1. json简介2. dumps/loads3. dump/load4. jsonl格式 1. json简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,用于在不同应用程序之间传递数据。它是一种文本格式,易于阅读和编写,同时也易于…...
Settingator:嵌入式参数管理库的轻量级设计与实践
1. Settingator 库概述:嵌入式设备与移动端配置协同的工程实践Settingator 是一个面向嵌入式系统的轻量级 Arduino 兼容库,其核心目标并非提供通用通信协议栈,而是构建一套可验证、可回滚、低侵入的运行时参数管理机制,专为配合同…...
linux学习进展 基础命令 vi基础命令
Linux系统的核心操作依赖命令行,掌握基础命令是入门Linux的关键,而vi编辑器作为Linux自带的文本编辑工具,日常使用频率极高。本次笔记主要记录Linux常用基础命令及vi编辑器的核心操作,方便后续复习巩固,兼顾实用性和易…...
基于雨流计数法的源-荷-储双层协同优化配置研究(Matlab代码实现)
👨🎓个人主页 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰&a…...
Claude Code 使用秘籍!从零基础到精通,字节跳动内部手册,小白也能秒懂!
本文提供了一份详尽的 Claude Code 使用手册,旨在帮助用户从零基础快速掌握该工具。手册内容步骤清晰,技巧实用,无需复杂代码知识即可上手。特别适合正在使用 Gemini3 的用户,以及希望了解字节跳动 Claude Code 中文使用的读者。获…...
告别对账熬夜,Captain AI帮你揪出Ozon的异常扣费
做Ozon的卖家,几乎都有过这样的经历:月底打开平台账单,密密麻麻全是俄语专业术语,看半天也看不懂每一笔钱扣在了哪里;熬一整个通宵核对账单,却还是算不清每一笔收支,找不到平台多扣的钱…...
瑞斯康达Raisecom交换机VLAN与ERPS实战配置指南
1. 瑞斯康达交换机基础配置入门 第一次接触瑞斯康达交换机的朋友可能会被命令行界面吓到,其实它的操作逻辑和主流厂商设备非常相似。以Gazelle系列交换机为例,默认登录账号密码都是raisecom,这个设计对新手特别友好——至少不用像某些品牌设备…...
WeChatMsg终极方案:构建个人微信数据管理中心
WeChatMsg终极方案:构建个人微信数据管理中心 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMsg …...
Android手电筒控制全攻略:从基础开关到状态监听(附完整代码)
Android手电筒控制全攻略:从基础开关到状态监听(附完整代码) 在移动应用开发中,手电筒功能看似简单,实则涉及相机硬件控制、状态同步、异常处理等多个技术要点。本文将带你深入Android手电筒控制的完整实现方案&#x…...
Windows系统指针美化全攻略:基于开源方案的跨平台实现
Windows系统指针美化全攻略:基于开源方案的跨平台实现 【免费下载链接】macOS-cursors-for-Windows Tested in Windows 10 & 11, 4K (125%, 150%, 200%). With 2 versions, 2 types and 3 different sizes! 项目地址: https://gitcode.com/gh_mirrors/ma/macO…...
如何解决Jellyfin番剧管理痛点?Bangumi插件的技术实现与应用指南
如何解决Jellyfin番剧管理痛点?Bangumi插件的技术实现与应用指南 【免费下载链接】jellyfin-plugin-bangumi bgm.tv plugin for jellyfin 项目地址: https://gitcode.com/gh_mirrors/je/jellyfin-plugin-bangumi Jellyfin作为开源媒体中心软件,在…...
