当前位置: 首页 > news >正文

C++之va_start、vasprintf、va_end应用总结(二百二十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:C++之va_start、vasprintf、va_end应用总结。

在C/C++语言中,va_startvasprintfva_end是与可变参数相关的函数。它们通常与stdarg.h头文件一起使用。

  1. va_start函数:

    • va_start函数用于初始化可变参数列表。它接受两个参数:第一个参数是一个va_list类型的变量,第二个参数是最后一个固定参数的前一个参数的名称。
    • 这个函数将va_list类型变量初始化为指向可变参数列表的起始位置。
  2. vasprintf函数:

    • vasprintf函数用于将格式化的可变参数输出到动态分配的字符串中。
    • 它接受两个参数:第一个参数是一个指向char指针的指针,第二个参数是一个格式化字符串。
    • 这个函数会根据格式化字符串和可变参数列表生成一个动态分配的字符串,并将指针保存在第一个参数所指向的位置。
  3. 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宏的工作原理如下:

  1. 首先,通过传入的参数列表的类型信息和格式化字符串来确定参数列表的起始位置。

  2. 然后,通过指针运算和类型大小来计算出参数列表中各个参数的位置。

  3. 最后,将参数列表位置信息保存在一个va_list类型的变量中,供后续函数进行处理。

va_start宏的实现通常依赖于编译器和操作系统的底层支持。它使用了一些机制来获取参数列表的信息,如栈帧结构、类型信息、指针运算等。

具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:

  1. 获取栈帧指针:va_start宏需要通过访问栈来获取参数列表的位置信息。它首先获取当前函数的栈帧指针,可以通过编译器提供的相关函数或底层汇编指令来实现。

  2. 计算参数列表位置:通过栈帧指针和参数类型大小,va_start宏可以计算出参数列表中各个参数的位置。这通常涉及指针运算,根据参数类型大小来移动指针位置。

  3. 保存参数列表信息: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宏的工作原理如下:

  1. 首先,它接收一个va_list类型的变量作为参数,该变量保存了参数列表的位置信息。

  2. 接着,通过一系列机制(如编译器和操作系统的底层支持)实现将参数列表进行清理和释放的操作。

  3. 最后,将va_list类型的变量标记为无效,以确保之后对它的访问是无效的。

具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:

  1. 清理参数列表:va_end宏根据参数列表的位置信息,使用特定的机制将参数列表进行清理。它可能涉及释放资源、清理栈上的参数值等操作。具体的清理操作由编译器和操作系统提供的底层支持来实现。

  2. 使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());
}
  1. vsnprintf函数接收一个格式化字符串和一个va_list类型的参数列表。利用格式化字符串,它将参数列表中的数据转换为相应的字符串格式。

  2. 首先,vsnprintf函数根据格式化字符串中的格式指示符,逐个读取参数列表的值,并根据指示符的要求对其进行格式化。

  3. 然后,vsnprintf函数根据格式化的结果,将其写入到指定的缓冲区中。它会确保写入的数据不超过指定的缓冲区大小。

  4. 最后,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应用总结(二百二十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…...

OpenCV自学笔记十一:形态学操作(一)

目录 1、腐蚀 2、膨胀 3、通用形态学函数 4、开运算 5、闭运算 1、腐蚀 腐蚀&#xff08;Erosion&#xff09;是数字图像处理中的一种形态学操作&#xff0c;用于消除图像中边界附近的细小区域或缩小对象的大小。腐蚀操作通过卷积输入图像与结构元素&#xff08;也称为腐…...

封装全局异常处理

文章目录 1 定义错误码类2 定义业务异常类3 全局异常处理器4 使用5 前端请求效果总结 1 定义错误码类 ​ 可以定义各种错误码枚举&#xff0c;比如业务&#xff0c;系统相关的报错信息 /*** 错误代码* 错误码** author leovany* date 2023/09/23*/ public enum ErrorCode {SU…...

python的requests响应请求,结果乱码,即使设置了response.encoding也没有用的解决方法

一、问题 如图&#xff1a; 一般出现乱码&#xff0c;我们会有三种解决方式&#xff0c;如下但是图中解决了发现还是不行, response.encodingresponse.apparent_encoding通过看网页源码对response.encodingutf8指定编码格式或者直接通过response.content.decode()来获得源码 出…...

PyCharm 手动下载插件

插件模块一直加载失败&#xff0c;报错信息&#xff1a; Marketplace plugins are not loaded. Check the internet connection and refresh. 尝试了以下方法&#xff0c;均告失败&#xff1a; pip 换源Manage Plugin Repositories...HTTP 代理设置...关闭三个防火墙 最后选…...

Gnomon绑定基础(约束 IK 节点)

点约束 方向约束 父约束 目标约束 修改后 对象方向 IK控制柄 直的骨骼&#xff0c;指定IK怎么弯曲 直的骨骼&#xff0c;指定IK怎么弯曲 样条曲线 数学节点 乘除节点 混合节点 注意...

STL常用遍历,查找,算法

目录 1.遍历算法 1.1for_earch 1.2transform 2.常用查找算法 2.1find&#xff0c;返回值是迭代器 2.1.1查找内置数据类型 2.1.2查找自定义数据类型 2.2fin_if 按条件查找元素 2.2.1查找内置的数据类型 2.2.2查找内置数据类型 2.3查找相邻元素adjeacent_find 2.4查找指…...

BCC源码内容概览(1)

接前一篇文章&#xff1a;BCC源码编译和安装 本文参考官网中的Contents部分的介绍。 BCC源码根目录的文件&#xff0c;其中一些是同时包含C和Python的单个文件&#xff0c;另一些是.c和.py的成对文件&#xff0c;还有一些是目录。 跟踪&#xff08;Tracing&#xff09; exam…...

mysql限制用户登录失败次数,限制时间

mysql用户登录限制设置 mysql 需要进行用户登录次数限制,当使用密码登录超过 3 次认证链接失败之后,登录锁住一段时间,禁止登录这里使用的 mysql: 8.1.0 这种方式不用重启数据库. 配置: 首先进入到 mysql 命令行:然后需要安装两个插件: 在 mysql 命令行中执行: mysql> INS…...

从利用Arthas排查线上Fastjson问题到Java动态字节码技术(下)

上一篇从Arthas的源码引出了Java动态字节码技术&#xff0c;那么这一篇就从几种Java字节码技术出发&#xff0c;看看Arthas是如何通过动态字节码技术做到无侵入的源码增强&#xff1b; Java大部分情况下都是解释执行的&#xff0c;也就是解释.class文件&#xff0c;所以如果我们…...

Ubuntu中安装Anaconda 如何将 路径导入为全局变量

第一步&#xff1a;将你的anaconda 路径复制下来&#xff0c;在终端输入对应路径。 echo export PATH"/home/你的用户名/anaconda3/bin:$PATH" >> ~/.bashrc 第二步&#xff1a;在终端输入下面命令或者重启系统。 source ~/.bashrc 在对应的anaconda安装目…...

【QT】Qt的随身笔记(持续更新...)

目录 Qt 获取当前电脑桌面的路径Qt 获取当前程序运行路径Qt 创建新的文本文件txt&#xff0c;并写入内容如何向QPlainTextEdit 写入内容QTimerQMessageBox的使用QLatin1StringQLayoutC在c头文件中写#include类的头文件与直接写class加类名有何区别mutable关键字前向声明 QFontQ…...

【LeetCode-简单题】589. N 叉树的前序遍历

文章目录 题目方法一&#xff1a;单循环栈做法方法二&#xff1a;递归 题目 方法一&#xff1a;单循环栈做法 关键在于子节点的入栈顺序&#xff0c;决定了子节点的出栈顺序&#xff0c; 因为是前序遍历 所以压栈顺序先让右边的入栈 依次往左 这样左边的节点会在栈顶 这样下次…...

Linphone3.5.2 ARM RV1109音视频对讲开发记录

Linphone3.5.2 ARM RV1109音视频对讲开发记录 说明 这是一份事后记录&#xff0c;主要记录的几个核心关键点&#xff0c;有可能很多细节没有记上&#xff0c;主要是方便后面自己再找回来! 版本 3.5.2 一些原因选的是这样一个旧的版本&#xff01; 新的开发最好选新一些的版…...

Unity用相机实现的镜子效果

首先登场 场景中的元素 mirror是镜子&#xff0c;挂着我们的脚本&#xff0c;Quad是一个面片。Camera是用来生成RenderTexture给面片的。里面的test1是我用来调试位置的球。 镜子size是大小&#xff0c;x是-2&#xff0c;为了反转一下贴图 相机直接可以禁用掉&#xff0c;用…...

计算机网络分类

按照覆盖范围分类 &#xff08;1&#xff09;个域网&#xff1a;通常覆盖范围在1&#xff5e;10m。 &#xff08;2&#xff09;局域网&#xff1a;通常覆盖范围在10m&#xff5e;1km。 &#xff08;3&#xff09;城域网&#xff1a;覆盖范围通常在5&#xff5e;50 km 。 &…...

AI AIgents时代 - (三.) AutoGPT和AgentGPT

前两篇讲解了Agent的原理和组件&#xff0c;这节我将给大家介绍两个agent项目&#xff0c;给出它们的工作原理和区别&#xff0c;并教大家亲手尝试使用 Agents&#x1f389; &#x1f7e2; AutoGPT&#x1f916;️ 我们的老朋友&#xff0c;之前文章也专门写过。AutoGPT 是一…...

Jmeter接口自动化和Python接口自动化,如何选择?

选择Jmeter或Python进行接口自动化测试取决于您的具体需求和环境。以下是一些可以考虑的因素&#xff1a; 1. 语言熟悉度&#xff1a;如果您对Java更熟悉&#xff0c;那么Jmeter可能是更好的选择。而如果您的团队或个人对Python更熟悉&#xff0c;那么Python可能是更好的选择。…...

Sqilte3初步教程

文章目录 安装创建数据库创建和删除表插入行数据 安装 Windows下安装&#xff0c;首先到下载页面&#xff0c;下载Windows安装软件&#xff0c;一般是 sqlite-dll-win32-*.zip sqlite-tools-win32-*.zip下载之后将其内容解压到同一个文件夹下&#xff0c;我把它们都放在了D:\…...

详解Python中的json库

目录 1. json简介2. dumps/loads3. dump/load4. jsonl格式 1. json简介 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;用于在不同应用程序之间传递数据。它是一种文本格式&#xff0c;易于阅读和编写&#xff0c;同时也易于…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...

结构化文件管理实战:实现目录自动创建与归类

手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题&#xff0c;进而引发后续程序异常。使用工具进行标准化操作&#xff0c;能有效降低出错概率。 需要快速整理大量文件的技术用户而言&#xff0c;这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB&#xff0c;…...